CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: hrydgard/ppsspp
Path: blob/master/Core/Dialog/PSPSaveDialog.cpp
Views: 1401
1
// Copyright (c) 2012- PPSSPP Project.
2
3
// This program is free software: you can redistribute it and/or modify
4
// it under the terms of the GNU General Public License as published by
5
// the Free Software Foundation, version 2.0 or later versions.
6
7
// This program is distributed in the hope that it will be useful,
8
// but WITHOUT ANY WARRANTY; without even the implied warranty of
9
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
// GNU General Public License 2.0 for more details.
11
12
// A copy of the GPL 2.0 should have been included with the program.
13
// If not, see http://www.gnu.org/licenses/
14
15
// Official git repository and contact information can be found at
16
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
17
18
#ifdef __MINGW32__
19
#include <unistd.h>
20
#ifndef _POSIX_THREAD_SAFE_FUNCTIONS
21
#define _POSIX_THREAD_SAFE_FUNCTIONS 200112L
22
#endif
23
#endif
24
25
#include <algorithm>
26
#include <ctime>
27
#include <thread>
28
29
#include "Common/Data/Encoding/Utf8.h"
30
#include "Common/Data/Text/I18n.h"
31
#include "Common/File/FileUtil.h"
32
#include "Common/Serialize/Serializer.h"
33
#include "Common/Serialize/SerializeFuncs.h"
34
#include "Common/StringUtils.h"
35
#include "Common/Thread/ThreadUtil.h"
36
#include "Core/Dialog/PSPSaveDialog.h"
37
#include "Core/FileSystems/MetaFileSystem.h"
38
#include "Core/Util/PPGeDraw.h"
39
#include "Core/HLE/sceCtrl.h"
40
#include "Core/HLE/sceUtility.h"
41
#include "Core/HW/MemoryStick.h"
42
#include "Core/MemMapHelpers.h"
43
#include "Core/Config.h"
44
#include "Core/Reporting.h"
45
#include "Core/SaveState.h"
46
47
const static float FONT_SCALE = 0.55f;
48
49
// These are rough, it seems to take at least 100ms or so to init, and shutdown depends on threads.
50
// Some games seem to required slightly longer delays to work, so we try 200ms as a compromise.
51
const static int SAVEDATA_INIT_DELAY_US = 200000;
52
const static int SAVEDATA_SHUTDOWN_DELAY_US = 2000;
53
54
// These are the only sizes which are allowed.
55
// TODO: We should test what the different behavior is for each.
56
const static int SAVEDATA_DIALOG_SIZE_V1 = 1480;
57
const static int SAVEDATA_DIALOG_SIZE_V2 = 1500;
58
const static int SAVEDATA_DIALOG_SIZE_V3 = 1536;
59
60
static bool IsNotVisibleAction(SceUtilitySavedataType type) {
61
switch (type) {
62
case SCE_UTILITY_SAVEDATA_TYPE_AUTOLOAD:
63
case SCE_UTILITY_SAVEDATA_TYPE_AUTOSAVE:
64
case SCE_UTILITY_SAVEDATA_TYPE_SIZES:
65
case SCE_UTILITY_SAVEDATA_TYPE_LIST:
66
case SCE_UTILITY_SAVEDATA_TYPE_FILES:
67
case SCE_UTILITY_SAVEDATA_TYPE_GETSIZE:
68
case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE:
69
case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATA:
70
case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE:
71
case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATA:
72
case SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE:
73
case SCE_UTILITY_SAVEDATA_TYPE_READDATA:
74
case SCE_UTILITY_SAVEDATA_TYPE_ERASESECURE:
75
case SCE_UTILITY_SAVEDATA_TYPE_ERASE:
76
case SCE_UTILITY_SAVEDATA_TYPE_DELETEDATA:
77
case SCE_UTILITY_SAVEDATA_TYPE_AUTODELETE:
78
return true;
79
80
default:
81
break;
82
}
83
return false;
84
}
85
86
PSPSaveDialog::PSPSaveDialog(UtilityDialogType type) : PSPDialog(type) {
87
param.SetPspParam(0);
88
}
89
90
PSPSaveDialog::~PSPSaveDialog() {
91
JoinIOThread();
92
}
93
94
int PSPSaveDialog::Init(int paramAddr)
95
{
96
// Ignore if already running
97
if (GetStatus() != SCE_UTILITY_STATUS_NONE) {
98
ERROR_LOG_REPORT(Log::sceUtility, "A save request is already running, not starting a new one");
99
return SCE_ERROR_UTILITY_INVALID_STATUS;
100
}
101
102
JoinIOThread();
103
ioThreadStatus = SAVEIO_NONE;
104
105
requestAddr = paramAddr;
106
int size = Memory::Read_U32(requestAddr);
107
memset(&request, 0, sizeof(request));
108
// Only copy the right size to support different save request format
109
if (size != SAVEDATA_DIALOG_SIZE_V1 && size != SAVEDATA_DIALOG_SIZE_V2 && size != SAVEDATA_DIALOG_SIZE_V3) {
110
ERROR_LOG_REPORT(Log::sceUtility, "sceUtilitySavedataInitStart: invalid size %d", size);
111
return SCE_ERROR_UTILITY_INVALID_PARAM_SIZE;
112
}
113
Memory::Memcpy(&request, requestAddr, size);
114
Memory::Memcpy(&originalRequest, requestAddr, size);
115
116
param.SetIgnoreTextures(IsNotVisibleAction((SceUtilitySavedataType)(u32)request.mode));
117
param.ClearSFOCache();
118
int retval = param.SetPspParam(&request);
119
120
const u32 mode = (u32)param.GetPspParam()->mode;
121
const char *modeName = mode < ARRAY_SIZE(utilitySavedataTypeNames) ? utilitySavedataTypeNames[mode] : "UNKNOWN";
122
INFO_LOG(Log::sceUtility,"sceUtilitySavedataInitStart(%08x) - %s (%d)", paramAddr, modeName, mode);
123
INFO_LOG(Log::sceUtility,"sceUtilitySavedataInitStart(%08x) : Game key (hex): %s", paramAddr, param.GetKey(param.GetPspParam()).c_str());
124
125
yesnoChoice = 1;
126
switch ((SceUtilitySavedataFocus)(u32)param.GetPspParam()->focus)
127
{
128
case SCE_UTILITY_SAVEDATA_FOCUS_NAME:
129
currentSelectedSave = param.GetSaveNameIndex(param.GetPspParam());
130
break;
131
case SCE_UTILITY_SAVEDATA_FOCUS_FIRSTLIST:
132
currentSelectedSave = param.GetFirstListSave();
133
break;
134
case SCE_UTILITY_SAVEDATA_FOCUS_LASTLIST:
135
currentSelectedSave = param.GetLastListSave();
136
break;
137
case SCE_UTILITY_SAVEDATA_FOCUS_LATEST:
138
currentSelectedSave = param.GetLatestSave();
139
break;
140
case SCE_UTILITY_SAVEDATA_FOCUS_OLDEST:
141
currentSelectedSave = param.GetOldestSave();
142
break;
143
case SCE_UTILITY_SAVEDATA_FOCUS_FIRSTDATA:
144
currentSelectedSave = param.GetFirstDataSave();
145
break;
146
case SCE_UTILITY_SAVEDATA_FOCUS_LASTDATA:
147
currentSelectedSave = param.GetLastDataSave();
148
break;
149
case SCE_UTILITY_SAVEDATA_FOCUS_FIRSTEMPTY:
150
currentSelectedSave = param.GetFirstEmptySave();
151
break;
152
case SCE_UTILITY_SAVEDATA_FOCUS_LASTEMPTY:
153
currentSelectedSave = param.GetLastEmptySave();
154
break;
155
default:
156
WARN_LOG(Log::sceUtility, "Unknown save list focus option: %d", param.GetPspParam()->focus);
157
currentSelectedSave = 0;
158
break;
159
}
160
161
if (!param.WouldHaveMultiSaveName(param.GetPspParam()))
162
currentSelectedSave = 0;
163
164
switch ((SceUtilitySavedataType)(u32)param.GetPspParam()->mode)
165
{
166
case SCE_UTILITY_SAVEDATA_TYPE_LOAD:
167
DEBUG_LOG(Log::sceUtility, "Loading. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetSaveName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str());
168
if (param.GetFileInfo(0).size != 0) {
169
if (param.GetFileInfo(0).broken) {
170
param.GetPspParam()->common.result = SCE_UTILITY_SAVEDATA_ERROR_LOAD_DATA_BROKEN;
171
display = DS_LOAD_FAILED;
172
} else {
173
display = DS_LOAD_CONFIRM;
174
}
175
} else
176
display = DS_LOAD_NODATA;
177
break;
178
case SCE_UTILITY_SAVEDATA_TYPE_AUTOLOAD:
179
DEBUG_LOG(Log::sceUtility, "Loading. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetSaveName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str());
180
display = DS_NONE;
181
// Is this necessary?
182
// currentSelectedSave = param.GetSelectedSave();
183
break;
184
case SCE_UTILITY_SAVEDATA_TYPE_LISTLOAD:
185
DEBUG_LOG(Log::sceUtility, "Loading. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str());
186
if(param.GetFilenameCount() == 0)
187
display = DS_LOAD_NODATA;
188
else
189
display = DS_LOAD_LIST_CHOICE;
190
break;
191
case SCE_UTILITY_SAVEDATA_TYPE_SAVE:
192
DEBUG_LOG(Log::sceUtility, "Saving. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str());
193
if (param.GetFileInfo(0).size != 0)
194
{
195
yesnoChoice = 0;
196
display = DS_SAVE_CONFIRM_OVERWRITE;
197
}
198
else
199
display = DS_SAVE_CONFIRM;
200
break;
201
case SCE_UTILITY_SAVEDATA_TYPE_AUTOSAVE:
202
DEBUG_LOG(Log::sceUtility, "Saving. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str());
203
display = DS_NONE;
204
// Is this necessary?
205
// currentSelectedSave = param.GetSelectedSave();
206
break;
207
case SCE_UTILITY_SAVEDATA_TYPE_LISTSAVE:
208
DEBUG_LOG(Log::sceUtility, "Saving. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str());
209
display = DS_SAVE_LIST_CHOICE;
210
break;
211
case SCE_UTILITY_SAVEDATA_TYPE_LISTALLDELETE:
212
DEBUG_LOG(Log::sceUtility, "Delete. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str());
213
if(param.GetFilenameCount() == 0)
214
display = DS_DELETE_NODATA;
215
else
216
display = DS_DELETE_LIST_CHOICE;
217
break;
218
case SCE_UTILITY_SAVEDATA_TYPE_SIZES:
219
case SCE_UTILITY_SAVEDATA_TYPE_LIST:
220
case SCE_UTILITY_SAVEDATA_TYPE_FILES:
221
case SCE_UTILITY_SAVEDATA_TYPE_GETSIZE:
222
case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE:
223
case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATA:
224
case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE:
225
case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATA:
226
case SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE:
227
case SCE_UTILITY_SAVEDATA_TYPE_READDATA:
228
case SCE_UTILITY_SAVEDATA_TYPE_ERASESECURE:
229
case SCE_UTILITY_SAVEDATA_TYPE_ERASE:
230
case SCE_UTILITY_SAVEDATA_TYPE_DELETEDATA:
231
display = DS_NONE;
232
break;
233
234
case SCE_UTILITY_SAVEDATA_TYPE_DELETE:
235
DEBUG_LOG(Log::sceUtility, "Delete. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str());
236
if (param.GetFileInfo(0).size != 0) {
237
yesnoChoice = 0;
238
display = DS_DELETE_CONFIRM;
239
} else
240
display = DS_DELETE_NODATA;
241
break;
242
243
case SCE_UTILITY_SAVEDATA_TYPE_AUTODELETE:
244
DEBUG_LOG(Log::sceUtility, "Delete. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str());
245
display = DS_NONE;
246
break;
247
248
case SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE:
249
DEBUG_LOG(Log::sceUtility, "Delete. Title: %s Save: %s File: %s", param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str());
250
if (param.GetFilenameCount() == 0)
251
display = DS_DELETE_NODATA;
252
else
253
display = DS_DELETE_LIST_CHOICE;
254
break;
255
default:
256
{
257
ERROR_LOG_REPORT(Log::sceUtility, "Load/Save function %d not coded. Title: %s Save: %s File: %s", (SceUtilitySavedataType)(u32)param.GetPspParam()->mode, param.GetGameName(param.GetPspParam()).c_str(), param.GetGameName(param.GetPspParam()).c_str(), param.GetFileName(param.GetPspParam()).c_str());
258
param.GetPspParam()->common.result = 0;
259
ChangeStatusInit(SAVEDATA_INIT_DELAY_US);
260
display = DS_NONE;
261
return 0; // Return 0 should allow the game to continue, but missing function must be implemented and returning the right value or the game can block.
262
}
263
break;
264
}
265
266
if (retval < 0) {
267
ChangeStatusShutdown(SAVEDATA_SHUTDOWN_DELAY_US);
268
} else {
269
ChangeStatusInit(SAVEDATA_INIT_DELAY_US);
270
}
271
272
param.ClearSFOCache();
273
InitCommon();
274
UpdateButtons();
275
StartFade(true);
276
277
/*INFO_LOG(Log::sceUtility,"Dump Param :");
278
INFO_LOG(Log::sceUtility,"size : %d",param.GetPspParam()->common.size);
279
INFO_LOG(Log::sceUtility,"language : %d",param.GetPspParam()->common.language);
280
INFO_LOG(Log::sceUtility,"buttonSwap : %d",param.GetPspParam()->common.buttonSwap);
281
INFO_LOG(Log::sceUtility,"result : %d",param.GetPspParam()->common.result);
282
INFO_LOG(Log::sceUtility,"mode : %d",param.GetPspParam()->mode);
283
INFO_LOG(Log::sceUtility,"bind : %d",param.GetPspParam()->bind);
284
INFO_LOG(Log::sceUtility,"overwriteMode : %d",param.GetPspParam()->overwriteMode);
285
INFO_LOG(Log::sceUtility,"gameName : %s",param.GetGameName(param.GetPspParam()).c_str());
286
INFO_LOG(Log::sceUtility,"saveName : %s",param.GetPspParam()->saveName);
287
INFO_LOG(Log::sceUtility,"saveNameList : %08x",*((unsigned int*)&param.GetPspParam()->saveNameList));
288
INFO_LOG(Log::sceUtility,"fileName : %s",param.GetPspParam()->fileName);
289
INFO_LOG(Log::sceUtility,"dataBuf : %08x",*((unsigned int*)&param.GetPspParam()->dataBuf));
290
INFO_LOG(Log::sceUtility,"dataBufSize : %u",param.GetPspParam()->dataBufSize);
291
INFO_LOG(Log::sceUtility,"dataSize : %u",param.GetPspParam()->dataSize);
292
293
INFO_LOG(Log::sceUtility,"sfo title : %s",param.GetPspParam()->sfoParam.title);
294
INFO_LOG(Log::sceUtility,"sfo savedataTitle : %s",param.GetPspParam()->sfoParam.savedataTitle);
295
INFO_LOG(Log::sceUtility,"sfo detail : %s",param.GetPspParam()->sfoParam.detail);
296
297
INFO_LOG(Log::sceUtility,"icon0 data : %08x",*((unsigned int*)&param.GetPspParam()->icon0FileData.buf));
298
INFO_LOG(Log::sceUtility,"icon0 size : %u",param.GetPspParam()->icon0FileData.bufSize);
299
300
INFO_LOG(Log::sceUtility,"icon1 data : %08x",*((unsigned int*)&param.GetPspParam()->icon1FileData.buf));
301
INFO_LOG(Log::sceUtility,"icon1 size : %u",param.GetPspParam()->icon1FileData.bufSize);
302
303
INFO_LOG(Log::sceUtility,"pic1 data : %08x",*((unsigned int*)&param.GetPspParam()->pic1FileData.buf));
304
INFO_LOG(Log::sceUtility,"pic1 size : %u",param.GetPspParam()->pic1FileData.bufSize);
305
306
INFO_LOG(Log::sceUtility,"snd0 data : %08x",*((unsigned int*)&param.GetPspParam()->snd0FileData.buf));
307
INFO_LOG(Log::sceUtility,"snd0 size : %u",param.GetPspParam()->snd0FileData.bufSize);*/
308
INFO_LOG(Log::sceUtility, "Return value: %d", retval);
309
return retval;
310
}
311
312
std::string PSPSaveDialog::GetSelectedSaveDirName() const
313
{
314
switch ((SceUtilitySavedataType)(u32)param.GetPspParam()->mode)
315
{
316
case SCE_UTILITY_SAVEDATA_TYPE_LOAD:
317
case SCE_UTILITY_SAVEDATA_TYPE_AUTOLOAD:
318
case SCE_UTILITY_SAVEDATA_TYPE_SAVE:
319
case SCE_UTILITY_SAVEDATA_TYPE_AUTOSAVE:
320
case SCE_UTILITY_SAVEDATA_TYPE_AUTODELETE:
321
case SCE_UTILITY_SAVEDATA_TYPE_DELETE:
322
return param.GetSaveDirName(param.GetPspParam());
323
324
case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE:
325
case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATA:
326
case SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE:
327
case SCE_UTILITY_SAVEDATA_TYPE_READDATA:
328
case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE:
329
case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATA:
330
case SCE_UTILITY_SAVEDATA_TYPE_ERASESECURE:
331
case SCE_UTILITY_SAVEDATA_TYPE_ERASE:
332
case SCE_UTILITY_SAVEDATA_TYPE_DELETEDATA:
333
return param.GetSaveDirName(param.GetPspParam());
334
335
// SIZES ignores saveName it seems.
336
337
default:
338
return param.GetSaveDirName(param.GetPspParam(), currentSelectedSave);
339
break;
340
}
341
}
342
343
void PSPSaveDialog::DisplayBanner(int which)
344
{
345
auto di = GetI18NCategory(I18NCat::DIALOG);
346
PPGeDrawRect(0, 0, 480, 23, CalcFadedColor(0x65636358));
347
348
PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_VCENTER, 0.6f);
349
textStyle.hasShadow = false;
350
351
std::string_view title;
352
switch (which) {
353
case DB_SAVE:
354
title = di->T("Save");
355
break;
356
case DB_LOAD:
357
title = di->T("Load");
358
break;
359
case DB_DELETE:
360
title = di->T("Delete");
361
break;
362
default:
363
title = "";
364
break;
365
}
366
// TODO: Draw a hexagon icon
367
PPGeDrawImage(10, 6, 12.0f, 12.0f, 1, 10, 1, 10, 10, 10, FadedImageStyle());
368
PPGeDrawText(title, 30, 11, textStyle);
369
}
370
371
void PSPSaveDialog::DisplaySaveList(bool canMove) {
372
std::lock_guard<std::mutex> guard(paramLock);
373
static int upFramesHeld = 0;
374
static int downFramesHeld = 0;
375
376
for (int displayCount = 0; displayCount < param.GetFilenameCount(); displayCount++) {
377
PPGeImageStyle imageStyle = FadedImageStyle();
378
auto fileInfo = param.GetFileInfo(displayCount);
379
380
if (fileInfo.size == 0 && fileInfo.texture && fileInfo.texture->IsValid())
381
imageStyle.color = CalcFadedColor(0xFF777777);
382
383
// Calc save image position on screen
384
float w, h, x;
385
float y = 97;
386
if (displayCount != currentSelectedSave) {
387
w = 81;
388
h = 45;
389
x = 58.5f;
390
} else {
391
w = 144;
392
h = 80;
393
x = 27;
394
}
395
if (displayCount < currentSelectedSave)
396
y -= 13 + 45 * (currentSelectedSave - displayCount);
397
else if (displayCount > currentSelectedSave)
398
y += 48 + 45 * (displayCount - currentSelectedSave);
399
400
// Skip if it's well outside the screen.
401
if (y > 472.0f || y < -200.0f)
402
continue;
403
404
int pad = 0;
405
if (fileInfo.texture != nullptr && fileInfo.texture->IsValid()) {
406
fileInfo.texture->SetTexture();
407
int tw = fileInfo.texture->Width();
408
int th = fileInfo.texture->Height();
409
float scale = (float)h / (float)th;
410
int scaledW = (int)(tw * scale);
411
pad = (w - scaledW) / 2;
412
w = scaledW;
413
414
PPGeDrawImage(x + pad, y, w, h, 0, 0, 1, 1, tw, th, imageStyle);
415
} else {
416
PPGeDrawRect(x, y, x + w, y + h, 0x88666666);
417
}
418
if (displayCount == currentSelectedSave) {
419
float b = 1.2f;
420
uint32_t bc = CalcFadedColor(0xD0FFFFFF);
421
PPGeDrawRect(x + pad - b, y - b, x + pad + w + b, y, bc); // top border
422
PPGeDrawRect(x + pad - b, y, x + pad, y + h, bc); // left border
423
PPGeDrawRect(x + pad - b, y + h, x + pad + w + b, y + h + b, bc); //bottom border
424
PPGeDrawRect(x + pad + w, y, x + pad + w + b, y + h, bc); //right border
425
}
426
PPGeSetDefaultTexture();
427
}
428
429
if (canMove) {
430
if ( (IsButtonPressed(CTRL_UP) || IsButtonHeld(CTRL_UP, upFramesHeld)) && currentSelectedSave > 0)
431
currentSelectedSave--;
432
433
else if ( (IsButtonPressed(CTRL_DOWN) || IsButtonHeld(CTRL_DOWN, downFramesHeld)) && currentSelectedSave < (param.GetFilenameCount() - 1))
434
currentSelectedSave++;
435
}
436
}
437
438
void PSPSaveDialog::DisplaySaveIcon(bool checkExists)
439
{
440
std::lock_guard<std::mutex> guard(paramLock);
441
PPGeImageStyle imageStyle = FadedImageStyle();
442
auto curSave = param.GetFileInfo(currentSelectedSave);
443
444
if (curSave.size == 0 && checkExists)
445
imageStyle.color = CalcFadedColor(0xFF777777);
446
447
// Calc save image position on screen
448
float w = 144;
449
float h = 80;
450
float x = 27;
451
float y = 97;
452
453
int tw = 256;
454
int th = 256;
455
if (curSave.texture != nullptr && curSave.texture->IsValid()) {
456
curSave.texture->SetTexture();
457
tw = curSave.texture->Width();
458
th = curSave.texture->Height();
459
float scale = (float)h / (float)th;
460
int scaledW = (int)(tw * scale);
461
x += (w - scaledW) / 2;
462
w = scaledW;
463
} else {
464
PPGeDisableTexture();
465
}
466
PPGeDrawImage(x, y, w, h, 0, 0, 1, 1, tw, th, imageStyle);
467
PPGeSetDefaultTexture();
468
}
469
470
static void FormatSaveHourMin(char *hour_time, size_t sz, const tm &t) {
471
const char *am_pm = "AM";
472
int hour = t.tm_hour;
473
switch (g_Config.iTimeFormat) {
474
case 1:
475
if (hour == 12) {
476
am_pm = "PM";
477
} else if (hour > 12) {
478
am_pm = "PM";
479
hour -= 12;
480
} else if (hour == 0) {
481
hour = 12;
482
}
483
snprintf(hour_time, sz, "%02d:%02d %s", hour, t.tm_min, am_pm);
484
break;
485
case 0:
486
default:
487
snprintf(hour_time, sz, "%02d:%02d", hour, t.tm_min);
488
break;
489
}
490
}
491
492
static void FormatSaveDate(char *date, size_t sz, const tm &t) {
493
int year = t.tm_year + 1900;
494
int month = t.tm_mon + 1;
495
switch (g_Config.iDateFormat) {
496
case 1:
497
snprintf(date, sz, "%02d/%02d/%04d", month, t.tm_mday, year);
498
break;
499
case 2:
500
snprintf(date, sz, "%02d/%02d/%04d", t.tm_mday, month, year);
501
break;
502
case 0:
503
default:
504
snprintf(date, sz, "%04d/%02d/%02d", year, month, t.tm_mday);
505
break;
506
}
507
}
508
509
void PSPSaveDialog::DisplaySaveDataInfo1() {
510
std::lock_guard<std::mutex> guard(paramLock);
511
const SaveFileInfo &saveInfo = param.GetFileInfo(currentSelectedSave);
512
PPGeStyle saveTitleStyle = FadedStyle(PPGeAlign::BOX_LEFT, 0.55f);
513
514
if (saveInfo.broken) {
515
auto di = GetI18NCategory(I18NCat::DIALOG);
516
PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_VCENTER, 0.6f);
517
PPGeDrawText(di->T("Corrupted Data"), 180, 136, textStyle);
518
PPGeDrawText(saveInfo.title, 175, 159, saveTitleStyle);
519
} else if (saveInfo.size == 0) {
520
auto di = GetI18NCategory(I18NCat::DIALOG);
521
PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_VCENTER, 0.6f);
522
PPGeDrawText(di->T("NEW DATA"), 180, 136, textStyle);
523
} else {
524
char hour_time[32];
525
FormatSaveHourMin(hour_time, sizeof(hour_time), saveInfo.modif_time);
526
527
char date_year[32];
528
FormatSaveDate(date_year, sizeof(date_year), saveInfo.modif_time);
529
530
s64 sizeK = saveInfo.size / 1024;
531
532
PPGeDrawRect(180, 136, 480, 137, CalcFadedColor(0xFFFFFFFF));
533
std::string titleTxt = saveInfo.title;
534
std::string timeTxt = StringFromFormat("%s %s %lld KB", date_year, hour_time, sizeK);
535
std::string saveTitleTxt = saveInfo.saveTitle;
536
std::string saveDetailTxt = saveInfo.saveDetail;
537
538
PPGeStyle titleStyle = FadedStyle(PPGeAlign::BOX_BOTTOM, 0.6f);
539
titleStyle.color = CalcFadedColor(0xFFC0C0C0);
540
PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_LEFT, 0.5f);
541
542
PPGeDrawText(titleTxt.c_str(), 180, 136, titleStyle);
543
PPGeDrawText(timeTxt.c_str(), 180, 137, textStyle);
544
PPGeDrawText(saveTitleTxt.c_str(), 175, 159, saveTitleStyle);
545
PPGeDrawTextWrapped(saveDetailTxt.c_str(), 175, 181, 480 - 175, 250 - 181, textStyle);
546
}
547
}
548
549
void PSPSaveDialog::DisplaySaveDataInfo2(bool showNewData) {
550
std::lock_guard<std::mutex> guard(paramLock);
551
552
tm modif_time;
553
const char *save_title;
554
u32 data_size;
555
556
if (showNewData || param.GetFileInfo(currentSelectedSave).size == 0) {
557
time_t t;
558
time(&t);
559
localtime_r(&t, &modif_time);
560
save_title = param.GetPspParam()->sfoParam.savedataTitle;
561
// TODO: Account for icon, etc., etc.
562
data_size = param.GetPspParam()->dataSize;
563
} else {
564
modif_time = param.GetFileInfo(currentSelectedSave).modif_time;
565
save_title = param.GetFileInfo(currentSelectedSave).saveTitle;
566
data_size = param.GetFileInfo(currentSelectedSave).size;
567
}
568
569
char hour_time[32];
570
FormatSaveHourMin(hour_time, sizeof(hour_time), modif_time);
571
572
char date_year[32];
573
FormatSaveDate(date_year, sizeof(date_year), modif_time);
574
575
s64 sizeK = data_size / 1024;
576
577
PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_LEFT, 0.5f);
578
std::string title = SanitizeUTF8(std::string(save_title, strnlen(save_title, 128)));
579
std::string saveinfoTxt = StringFromFormat("%s\n%s %s\n%lld KB", title.c_str(), date_year, hour_time, sizeK);
580
PPGeDrawText(saveinfoTxt.c_str(), 8, 200, textStyle);
581
}
582
583
void PSPSaveDialog::DisplayMessage(std::string_view text, bool hasYesNo)
584
{
585
PPGeStyle textStyle = FadedStyle(PPGeAlign::BOX_CENTER, FONT_SCALE);
586
587
const float WRAP_WIDTH = 254.0f;
588
float y = 136.0f, h;
589
PPGeMeasureText(nullptr, &h, text, FONT_SCALE, PPGE_LINE_WRAP_WORD, WRAP_WIDTH);
590
float h2 = h / 2.0f;
591
if (hasYesNo)
592
{
593
auto di = GetI18NCategory(I18NCat::DIALOG);
594
std::string_view choiceText;
595
float x, w;
596
if (yesnoChoice == 1) {
597
choiceText = di->T("Yes");
598
x = 302.0f;
599
}
600
else {
601
choiceText = di->T("No");
602
x = 366.0f;
603
}
604
PPGeMeasureText(&w, &h, choiceText, FONT_SCALE);
605
w = w / 2.0f + 5.5f;
606
h /= 2.0f;
607
float y2 = y + h2 + 4.0f;
608
h2 += h + 4.0f;
609
y = 132.0f - h;
610
PPGeDrawRect(x - w, y2 - h, x + w, y2 + h, CalcFadedColor(0x40C0C0C0));
611
PPGeDrawText(di->T("Yes"), 302.0f, y2, textStyle);
612
PPGeDrawText(di->T("No"), 366.0f, y2, textStyle);
613
if (IsButtonPressed(CTRL_LEFT) && yesnoChoice == 0) {
614
yesnoChoice = 1;
615
}
616
else if (IsButtonPressed(CTRL_RIGHT) && yesnoChoice == 1) {
617
yesnoChoice = 0;
618
}
619
}
620
PPGeDrawTextWrapped(text, 334.0f, y, WRAP_WIDTH, 0, textStyle);
621
float sy = 122.0f - h2, ey = 150.0f + h2;
622
PPGeDrawRect(202.0f, sy, 466.0f, sy + 1.0f, CalcFadedColor(0xFFFFFFFF));
623
PPGeDrawRect(202.0f, ey, 466.0f, ey + 1.0f, CalcFadedColor(0xFFFFFFFF));
624
}
625
626
int PSPSaveDialog::Update(int animSpeed)
627
{
628
if (GetStatus() != SCE_UTILITY_STATUS_RUNNING)
629
return SCE_ERROR_UTILITY_INVALID_STATUS;
630
631
if (!param.GetPspParam()) {
632
ChangeStatusShutdown(SAVEDATA_SHUTDOWN_DELAY_US);
633
return 0;
634
}
635
636
if (pendingStatus != SCE_UTILITY_STATUS_RUNNING) {
637
// We're actually done, we're just waiting to tell the game that.
638
return 0;
639
}
640
641
// The struct may have been updated by the game. This happens in "Where Is My Heart?"
642
// Check if it has changed, reload it.
643
// TODO: Cut down on preloading? This rebuilds the list from scratch.
644
int size = std::min((u32)sizeof(originalRequest), Memory::Read_U32(requestAddr));
645
const u8 *updatedRequest = Memory::GetPointerRange(requestAddr, size);
646
if (updatedRequest && memcmp(updatedRequest, &originalRequest, size) != 0) {
647
memset(&request, 0, sizeof(request));
648
Memory::Memcpy(&request, requestAddr, size);
649
Memory::Memcpy(&originalRequest, requestAddr, size);
650
std::lock_guard<std::mutex> guard(paramLock);
651
param.SetPspParam(&request);
652
}
653
654
param.ClearSFOCache();
655
UpdateButtons();
656
UpdateFade(animSpeed);
657
658
UpdateCommon();
659
660
auto di = GetI18NCategory(I18NCat::DIALOG);
661
662
switch (display)
663
{
664
case DS_SAVE_LIST_CHOICE:
665
StartDraw();
666
667
DisplaySaveList();
668
DisplaySaveDataInfo1();
669
670
DisplayButtons(DS_BUTTON_OK | DS_BUTTON_CANCEL);
671
DisplayBanner(DB_SAVE);
672
673
if (IsButtonPressed(cancelButtonFlag)) {
674
param.GetPspParam()->common.result = SCE_UTILITY_DIALOG_RESULT_CANCEL;
675
StartFade(false);
676
} else if (IsButtonPressed(okButtonFlag)) {
677
// Save exist, ask user confirm
678
if (param.GetFileInfo(currentSelectedSave).size > 0) {
679
yesnoChoice = 0;
680
display = DS_SAVE_CONFIRM_OVERWRITE;
681
} else {
682
display = DS_SAVE_SAVING;
683
StartIOThread();
684
}
685
}
686
EndDraw();
687
break;
688
case DS_SAVE_CONFIRM:
689
StartDraw();
690
691
DisplaySaveIcon(false);
692
DisplaySaveDataInfo2(true);
693
694
DisplayMessage(di->T("Confirm Save", "Do you want to save this data?"), true);
695
696
DisplayButtons(DS_BUTTON_OK | DS_BUTTON_CANCEL);
697
DisplayBanner(DB_SAVE);
698
699
if (IsButtonPressed(cancelButtonFlag) || (IsButtonPressed(okButtonFlag) && yesnoChoice == 0)) {
700
param.GetPspParam()->common.result = SCE_UTILITY_DIALOG_RESULT_CANCEL;
701
StartFade(false);
702
} else if (IsButtonPressed(okButtonFlag)) {
703
display = DS_SAVE_SAVING;
704
StartIOThread();
705
}
706
707
EndDraw();
708
break;
709
case DS_SAVE_CONFIRM_OVERWRITE:
710
StartDraw();
711
712
DisplaySaveIcon(true);
713
DisplaySaveDataInfo2();
714
715
DisplayMessage(di->T("Confirm Overwrite","Do you want to overwrite the data?"), true);
716
717
DisplayButtons(DS_BUTTON_OK | DS_BUTTON_CANCEL);
718
DisplayBanner(DB_SAVE);
719
720
if (IsButtonPressed(cancelButtonFlag) || (IsButtonPressed(okButtonFlag) && yesnoChoice == 0)) {
721
if (param.GetPspParam()->mode != SCE_UTILITY_SAVEDATA_TYPE_SAVE)
722
display = DS_SAVE_LIST_CHOICE;
723
else {
724
param.GetPspParam()->common.result = SCE_UTILITY_DIALOG_RESULT_CANCEL;
725
StartFade(false);
726
}
727
} else if (IsButtonPressed(okButtonFlag)) {
728
display = DS_SAVE_SAVING;
729
StartIOThread();
730
}
731
732
EndDraw();
733
break;
734
case DS_SAVE_SAVING:
735
if (ioThreadStatus != SAVEIO_PENDING) {
736
JoinIOThread();
737
}
738
739
StartDraw();
740
741
DisplaySaveIcon(true);
742
DisplaySaveDataInfo2(true);
743
744
DisplayMessage(di->T("Saving","Saving\nPlease Wait..."));
745
746
DisplayBanner(DB_SAVE);
747
748
EndDraw();
749
break;
750
case DS_SAVE_FAILED:
751
JoinIOThread();
752
StartDraw();
753
754
DisplaySaveIcon(true);
755
DisplaySaveDataInfo2(true);
756
757
DisplayMessage(di->T("SavingFailed", "Unable to save data."));
758
759
DisplayButtons(DS_BUTTON_CANCEL);
760
DisplayBanner(DB_SAVE);
761
762
if (IsButtonPressed(cancelButtonFlag)) {
763
// Go back to the list so they can try again.
764
if (param.GetPspParam()->mode != SCE_UTILITY_SAVEDATA_TYPE_SAVE) {
765
display = DS_SAVE_LIST_CHOICE;
766
} else {
767
param.GetPspParam()->common.result = SCE_UTILITY_DIALOG_RESULT_CANCEL;
768
StartFade(false);
769
}
770
}
771
772
EndDraw();
773
break;
774
case DS_SAVE_DONE:
775
if (ioThread) {
776
JoinIOThread();
777
param.SetPspParam(param.GetPspParam());
778
}
779
StartDraw();
780
781
DisplaySaveIcon(true);
782
DisplaySaveDataInfo2();
783
784
DisplayMessage(di->T("Save completed"));
785
786
DisplayButtons(DS_BUTTON_CANCEL);
787
DisplayBanner(DB_SAVE);
788
789
if (IsButtonPressed(cancelButtonFlag)) {
790
param.GetPspParam()->common.result = SCE_UTILITY_DIALOG_RESULT_SUCCESS;
791
// Set the save to use for autosave and autoload
792
param.SetSelectedSave(param.GetFileInfo(currentSelectedSave).idx);
793
StartFade(false);
794
}
795
796
EndDraw();
797
break;
798
799
case DS_LOAD_LIST_CHOICE:
800
StartDraw();
801
802
DisplaySaveList();
803
DisplaySaveDataInfo1();
804
805
DisplayButtons(DS_BUTTON_OK | DS_BUTTON_CANCEL);
806
DisplayBanner(DB_LOAD);
807
808
if (IsButtonPressed(cancelButtonFlag)) {
809
param.GetPspParam()->common.result = SCE_UTILITY_DIALOG_RESULT_CANCEL;
810
StartFade(false);
811
} else if (IsButtonPressed(okButtonFlag)) {
812
display = DS_LOAD_LOADING;
813
StartIOThread();
814
}
815
816
EndDraw();
817
break;
818
case DS_LOAD_CONFIRM:
819
StartDraw();
820
821
DisplaySaveIcon(true);
822
DisplaySaveDataInfo2();
823
824
DisplayMessage(di->T("ConfirmLoad", "Load this data?"), true);
825
826
DisplayButtons(DS_BUTTON_OK | DS_BUTTON_CANCEL);
827
DisplayBanner(DB_LOAD);
828
829
if (IsButtonPressed(cancelButtonFlag) || (IsButtonPressed(okButtonFlag) && yesnoChoice == 0)) {
830
param.GetPspParam()->common.result = SCE_UTILITY_DIALOG_RESULT_CANCEL;
831
StartFade(false);
832
} else if (IsButtonPressed(okButtonFlag)) {
833
display = DS_LOAD_LOADING;
834
StartIOThread();
835
}
836
837
EndDraw();
838
break;
839
case DS_LOAD_LOADING:
840
if (ioThreadStatus != SAVEIO_PENDING) {
841
JoinIOThread();
842
}
843
844
StartDraw();
845
846
DisplaySaveIcon(true);
847
DisplaySaveDataInfo2();
848
849
DisplayMessage(di->T("Loading","Loading\nPlease Wait..."));
850
851
DisplayBanner(DB_LOAD);
852
853
EndDraw();
854
break;
855
case DS_LOAD_FAILED:
856
JoinIOThread();
857
StartDraw();
858
859
DisplaySaveIcon(true);
860
DisplaySaveDataInfo2();
861
862
DisplayMessage(di->T("LoadingFailed", "Load failed\nThe data is corrupted."));
863
864
DisplayButtons(DS_BUTTON_CANCEL);
865
DisplayBanner(DB_LOAD);
866
867
if (IsButtonPressed(cancelButtonFlag)) {
868
// Go back to the list so they can try again.
869
if (param.GetPspParam()->mode != SCE_UTILITY_SAVEDATA_TYPE_LOAD) {
870
display = DS_LOAD_LIST_CHOICE;
871
} else {
872
StartFade(false);
873
}
874
}
875
876
EndDraw();
877
break;
878
case DS_LOAD_DONE:
879
JoinIOThread();
880
StartDraw();
881
882
DisplaySaveIcon(true);
883
DisplaySaveDataInfo2();
884
885
DisplayMessage(di->T("Load completed"));
886
887
DisplayButtons(DS_BUTTON_CANCEL);
888
DisplayBanner(DB_LOAD);
889
890
// Allow OK to be pressed as well to confirm the save.
891
// The PSP only allows cancel, but that's generally not great UX.
892
// Allowing this here makes it quicker for most users to get into the actual game.
893
if (IsButtonPressed(cancelButtonFlag) || IsButtonPressed(okButtonFlag)) {
894
param.GetPspParam()->common.result = SCE_UTILITY_DIALOG_RESULT_SUCCESS;
895
// Set the save to use for autosave and autoload
896
param.SetSelectedSave(param.GetFileInfo(currentSelectedSave).idx);
897
StartFade(false);
898
}
899
900
EndDraw();
901
break;
902
case DS_LOAD_NODATA:
903
StartDraw();
904
905
DisplayMessage(di->T("There is no data"));
906
907
DisplayButtons(DS_BUTTON_CANCEL);
908
DisplayBanner(DB_LOAD);
909
910
if (IsButtonPressed(cancelButtonFlag)) {
911
param.GetPspParam()->common.result = SCE_UTILITY_SAVEDATA_ERROR_LOAD_NO_DATA;
912
StartFade(false);
913
}
914
915
EndDraw();
916
break;
917
918
case DS_DELETE_LIST_CHOICE:
919
StartDraw();
920
921
DisplaySaveList();
922
DisplaySaveDataInfo1();
923
924
DisplayButtons(DS_BUTTON_OK | DS_BUTTON_CANCEL);
925
DisplayBanner(DB_DELETE);
926
927
if (IsButtonPressed(cancelButtonFlag)) {
928
param.GetPspParam()->common.result = SCE_UTILITY_DIALOG_RESULT_CANCEL;
929
StartFade(false);
930
} else if (IsButtonPressed(okButtonFlag)) {
931
yesnoChoice = 0;
932
display = DS_DELETE_CONFIRM;
933
}
934
935
EndDraw();
936
break;
937
case DS_DELETE_CONFIRM:
938
StartDraw();
939
940
DisplaySaveIcon(true);
941
DisplaySaveDataInfo2();
942
943
DisplayMessage(di->T("DeleteConfirm",
944
"This save data will be deleted.\nAre you sure you want to continue?"),
945
true);
946
947
DisplayButtons(DS_BUTTON_OK | DS_BUTTON_CANCEL);
948
DisplayBanner(DB_DELETE);
949
950
if (IsButtonPressed(cancelButtonFlag) || (IsButtonPressed(okButtonFlag) && yesnoChoice == 0)) {
951
if(param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE || param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_LISTALLDELETE)
952
display = DS_DELETE_LIST_CHOICE;
953
else {
954
param.GetPspParam()->common.result = SCE_UTILITY_DIALOG_RESULT_CANCEL;
955
StartFade(false);
956
}
957
} else if (IsButtonPressed(okButtonFlag)) {
958
display = DS_DELETE_DELETING;
959
StartIOThread();
960
}
961
962
EndDraw();
963
break;
964
case DS_DELETE_DELETING:
965
if (ioThreadStatus != SAVEIO_PENDING) {
966
JoinIOThread();
967
}
968
969
StartDraw();
970
971
DisplayMessage(di->T("Deleting","Deleting\nPlease Wait..."));
972
973
DisplayBanner(DB_DELETE);
974
975
EndDraw();
976
break;
977
case DS_DELETE_FAILED:
978
JoinIOThread();
979
StartDraw();
980
981
DisplayMessage(di->T("DeleteFailed", "Unable to delete data."));
982
983
DisplayButtons(DS_BUTTON_CANCEL);
984
DisplayBanner(DB_DELETE);
985
986
if (IsButtonPressed(cancelButtonFlag)) {
987
if (param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE || param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_LISTALLDELETE)
988
display = DS_DELETE_LIST_CHOICE;
989
else
990
StartFade(false);
991
}
992
993
EndDraw();
994
break;
995
case DS_DELETE_DONE:
996
if (ioThread) {
997
JoinIOThread();
998
param.SetPspParam(param.GetPspParam());
999
}
1000
StartDraw();
1001
1002
DisplayMessage(di->T("Delete completed"));
1003
1004
DisplayButtons(DS_BUTTON_CANCEL);
1005
DisplayBanner(DB_DELETE);
1006
1007
if (IsButtonPressed(cancelButtonFlag)) {
1008
if (param.GetFilenameCount() == 0)
1009
display = DS_DELETE_NODATA;
1010
else if (param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_LISTDELETE || param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_LISTALLDELETE) {
1011
if (currentSelectedSave > param.GetFilenameCount() - 1)
1012
currentSelectedSave = param.GetFilenameCount() - 1;
1013
display = DS_DELETE_LIST_CHOICE;
1014
} else {
1015
param.GetPspParam()->common.result = SCE_UTILITY_DIALOG_RESULT_SUCCESS;
1016
StartFade(false);
1017
}
1018
}
1019
1020
EndDraw();
1021
break;
1022
case DS_DELETE_NODATA:
1023
StartDraw();
1024
1025
DisplayMessage(di->T("There is no data"));
1026
1027
DisplayButtons(DS_BUTTON_CANCEL);
1028
DisplayBanner(DB_DELETE);
1029
1030
if (IsButtonPressed(cancelButtonFlag)) {
1031
param.GetPspParam()->common.result = SCE_UTILITY_SAVEDATA_ERROR_DELETE_NO_DATA;
1032
StartFade(false);
1033
}
1034
1035
EndDraw();
1036
break;
1037
1038
case DS_NONE: // For action which display nothing
1039
switch (ioThreadStatus) {
1040
case SAVEIO_NONE:
1041
StartIOThread();
1042
break;
1043
case SAVEIO_PENDING:
1044
case SAVEIO_DONE:
1045
// To make sure there aren't any timing variations, we sync the next frame.
1046
if (g_Config.iIOTimingMethod == IOTIMING_HOST && ioThreadStatus == SAVEIO_PENDING) {
1047
// ... except in Host IO timing, where we wait as long as needed.
1048
break;
1049
}
1050
JoinIOThread();
1051
ChangeStatus(SCE_UTILITY_STATUS_FINISHED, 0);
1052
break;
1053
}
1054
break;
1055
1056
default:
1057
ChangeStatus(SCE_UTILITY_STATUS_FINISHED, 0);
1058
break;
1059
}
1060
1061
if (ReadStatus() == SCE_UTILITY_STATUS_FINISHED || pendingStatus == SCE_UTILITY_STATUS_FINISHED)
1062
Memory::Memcpy(requestAddr, &request, request.common.size, "SaveDialogParam");
1063
param.ClearSFOCache();
1064
1065
return 0;
1066
}
1067
1068
void PSPSaveDialog::ExecuteIOAction() {
1069
param.ClearSFOCache();
1070
auto &result = param.GetPspParam()->common.result;
1071
std::lock_guard<std::mutex> guard(paramLock);
1072
switch (display) {
1073
case DS_LOAD_LOADING:
1074
result = param.Load(param.GetPspParam(), GetSelectedSaveDirName(), currentSelectedSave);
1075
if (result == 0) {
1076
display = DS_LOAD_DONE;
1077
} else {
1078
display = DS_LOAD_FAILED;
1079
}
1080
break;
1081
case DS_SAVE_SAVING:
1082
SaveState::NotifySaveData();
1083
if (param.Save(param.GetPspParam(), GetSelectedSaveDirName()) == 0) {
1084
display = DS_SAVE_DONE;
1085
} else {
1086
display = DS_SAVE_FAILED;
1087
}
1088
break;
1089
case DS_DELETE_DELETING:
1090
if (param.Delete(param.GetPspParam(), currentSelectedSave)) {
1091
result = 0;
1092
display = DS_DELETE_DONE;
1093
} else {
1094
//result = SCE_UTILITY_SAVEDATA_ERROR_DELETE_NO_DATA;// What the result should be?
1095
display = DS_DELETE_FAILED;
1096
}
1097
break;
1098
case DS_NONE:
1099
ExecuteNotVisibleIOAction();
1100
break;
1101
1102
default:
1103
// Nothing to do here.
1104
break;
1105
}
1106
1107
ioThreadStatus = SAVEIO_DONE;
1108
param.ClearSFOCache();
1109
}
1110
1111
void PSPSaveDialog::ExecuteNotVisibleIOAction() {
1112
param.ClearSFOCache();
1113
auto &result = param.GetPspParam()->common.result;
1114
1115
SceUtilitySavedataType utilityMode = (SceUtilitySavedataType)(u32)param.GetPspParam()->mode;
1116
switch (utilityMode) {
1117
case SCE_UTILITY_SAVEDATA_TYPE_LOAD: // Only load and exit
1118
case SCE_UTILITY_SAVEDATA_TYPE_AUTOLOAD:
1119
result = param.Load(param.GetPspParam(), GetSelectedSaveDirName(), currentSelectedSave);
1120
break;
1121
case SCE_UTILITY_SAVEDATA_TYPE_SAVE: // Only save and exit
1122
case SCE_UTILITY_SAVEDATA_TYPE_AUTOSAVE:
1123
SaveState::NotifySaveData();
1124
result = param.Save(param.GetPspParam(), GetSelectedSaveDirName());
1125
break;
1126
case SCE_UTILITY_SAVEDATA_TYPE_SIZES:
1127
result = param.GetSizes(param.GetPspParam());
1128
break;
1129
case SCE_UTILITY_SAVEDATA_TYPE_LIST:
1130
param.GetList(param.GetPspParam());
1131
result = 0;
1132
break;
1133
case SCE_UTILITY_SAVEDATA_TYPE_FILES:
1134
result = param.GetFilesList(param.GetPspParam(), requestAddr);
1135
break;
1136
case SCE_UTILITY_SAVEDATA_TYPE_GETSIZE:
1137
{
1138
bool sizeResult = param.GetSize(param.GetPspParam());
1139
// TODO: According to JPCSP, should test/verify this part but seems edge casey.
1140
if (MemoryStick_State() != PSP_MEMORYSTICK_STATE_INSERTED) {
1141
result = SCE_UTILITY_SAVEDATA_ERROR_RW_NO_MEMSTICK;
1142
} else if (sizeResult) {
1143
result = 0;
1144
} else {
1145
result = SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA;
1146
}
1147
}
1148
break;
1149
case SCE_UTILITY_SAVEDATA_TYPE_DELETEDATA:
1150
DEBUG_LOG(Log::sceUtility, "sceUtilitySavedata DELETEDATA: %s", param.GetPspParam()->saveName);
1151
if (param.Delete(param.GetPspParam(), param.GetSelectedSave())) {
1152
result = 0;
1153
} else {
1154
result = SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA;
1155
}
1156
break;
1157
case SCE_UTILITY_SAVEDATA_TYPE_AUTODELETE:
1158
case SCE_UTILITY_SAVEDATA_TYPE_DELETE:
1159
if (param.Delete(param.GetPspParam(), param.GetSelectedSave())) {
1160
result = 0;
1161
} else {
1162
result = SCE_UTILITY_SAVEDATA_ERROR_DELETE_NO_DATA;
1163
}
1164
break;
1165
// TODO: Should reset the directory's other files.
1166
case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATA:
1167
case SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE:
1168
SaveState::NotifySaveData();
1169
result = param.Save(param.GetPspParam(), GetSelectedSaveDirName(), param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_MAKEDATASECURE);
1170
if (result == SCE_UTILITY_SAVEDATA_ERROR_SAVE_MS_NOSPACE) {
1171
result = SCE_UTILITY_SAVEDATA_ERROR_RW_MEMSTICK_FULL;
1172
}
1173
break;
1174
case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATA:
1175
case SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE:
1176
SaveState::NotifySaveData();
1177
result = param.Save(param.GetPspParam(), GetSelectedSaveDirName(), param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_WRITEDATASECURE);
1178
break;
1179
case SCE_UTILITY_SAVEDATA_TYPE_READDATA:
1180
case SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE:
1181
result = param.Load(param.GetPspParam(), GetSelectedSaveDirName(), currentSelectedSave, param.GetPspParam()->mode == SCE_UTILITY_SAVEDATA_TYPE_READDATASECURE);
1182
if (result == SCE_UTILITY_SAVEDATA_ERROR_LOAD_DATA_BROKEN)
1183
result = SCE_UTILITY_SAVEDATA_ERROR_RW_DATA_BROKEN;
1184
if (result == SCE_UTILITY_SAVEDATA_ERROR_LOAD_NO_DATA)
1185
result = SCE_UTILITY_SAVEDATA_ERROR_RW_NO_DATA;
1186
break;
1187
case SCE_UTILITY_SAVEDATA_TYPE_ERASE:
1188
case SCE_UTILITY_SAVEDATA_TYPE_ERASESECURE:
1189
result = param.DeleteData(param.GetPspParam());
1190
break;
1191
default:
1192
break;
1193
}
1194
1195
param.ClearSFOCache();
1196
}
1197
1198
void PSPSaveDialog::JoinIOThread() {
1199
if (ioThread) {
1200
ioThread->join();
1201
delete ioThread;
1202
ioThread = 0;
1203
}
1204
}
1205
1206
static void DoExecuteIOAction(PSPSaveDialog *dialog) {
1207
SetCurrentThreadName("SaveIO");
1208
1209
AndroidJNIThreadContext jniContext;
1210
dialog->ExecuteIOAction();
1211
}
1212
1213
void PSPSaveDialog::StartIOThread() {
1214
if (ioThread) {
1215
WARN_LOG_REPORT(Log::sceUtility, "Starting a save io thread when one already pending, uh oh.");
1216
JoinIOThread();
1217
}
1218
1219
ioThreadStatus = SAVEIO_PENDING;
1220
ioThread = new std::thread(&DoExecuteIOAction, this);
1221
}
1222
1223
int PSPSaveDialog::Shutdown(bool force) {
1224
if (GetStatus() != SCE_UTILITY_STATUS_FINISHED && !force)
1225
return SCE_ERROR_UTILITY_INVALID_STATUS;
1226
1227
JoinIOThread();
1228
ioThreadStatus = SAVEIO_NONE;
1229
1230
PSPDialog::Shutdown(force);
1231
if (!force) {
1232
ChangeStatusShutdown(SAVEDATA_SHUTDOWN_DELAY_US);
1233
}
1234
param.SetPspParam(0);
1235
param.ClearSFOCache();
1236
1237
return 0;
1238
}
1239
1240
void PSPSaveDialog::DoState(PointerWrap &p) {
1241
JoinIOThread();
1242
PSPDialog::DoState(p);
1243
1244
auto s = p.Section("PSPSaveDialog", 1, 2);
1245
if (!s) {
1246
return;
1247
}
1248
1249
Do(p, display);
1250
param.DoState(p);
1251
Do(p, request);
1252
// Just reset it.
1253
bool hasParam = param.GetPspParam() != NULL;
1254
Do(p, hasParam);
1255
if (hasParam && p.mode == p.MODE_READ) {
1256
param.SetPspParam(&request);
1257
}
1258
Do(p, requestAddr);
1259
Do(p, currentSelectedSave);
1260
Do(p, yesnoChoice);
1261
if (s > 2) {
1262
Do(p, ioThreadStatus);
1263
} else {
1264
ioThreadStatus = SAVEIO_NONE;
1265
}
1266
}
1267
1268
pspUtilityDialogCommon *PSPSaveDialog::GetCommonParam() {
1269
return &param.GetPspParam()->common;
1270
}
1271
1272