Rewrite Save Data & Impl Save Data Dialog (#824)

* core: Rewrite PSF parser & add encoder

add .sfo hex pattern to /scripts

* core/fs: allow to mount path as read-only

* common: Add CString wrapper to handle native null-terminated strings

* SaveData: rewrite to implement full functionality

* mock value for SYSTEM_VER

* SavaData: backup features

* SavaData: SaveDataMemory features

* imgui Ref-counted textures

- has a background thread to decode textures

* imgui: rework gamepad navigation

* PSF: fixed psf not using enum class for PSFEntryFmt (was a standard old ugly enum)

- Add null check to CString when itself is used in a nullable field

* SaveDataDialog implementation

- Fix Mounting/Unmounting check of SaveInstance
This commit is contained in:
Vinicius Rangel 2024-09-20 06:34:19 -03:00 committed by GitHub
parent 077f8981a7
commit 0f4bcd8c83
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
51 changed files with 4919 additions and 1134 deletions

View file

@ -27,20 +27,21 @@ public:
game.path = filePath;
PSF psf;
if (psf.open(game.path + "/sce_sys/param.sfo", {})) {
if (psf.Open(std::filesystem::path(game.path) / "sce_sys" / "param.sfo")) {
game.icon_path = game.path + "/sce_sys/icon0.png";
QString iconpath = QString::fromStdString(game.icon_path);
game.icon = QImage(iconpath);
game.pic_path = game.path + "/sce_sys/pic1.png";
game.name = psf.GetString("TITLE");
game.serial = psf.GetString("TITLE_ID");
game.region = GameListUtils::GetRegion(psf.GetString("CONTENT_ID").at(0)).toStdString();
u32 fw_int = psf.GetInteger("SYSTEM_VER");
game.name = *psf.GetString("TITLE");
game.serial = *psf.GetString("TITLE_ID");
game.region =
GameListUtils::GetRegion(psf.GetString("CONTENT_ID")->at(0)).toStdString();
u32 fw_int = *psf.GetInteger("SYSTEM_VER");
QString fw = QString::number(fw_int, 16);
QString fw_ = fw.length() > 7 ? QString::number(fw_int, 16).left(3).insert(2, '.')
: fw.left(3).insert(1, '.');
game.fw = (fw_int == 0) ? "0.00" : fw_.toStdString();
game.version = psf.GetString("APP_VER");
game.version = *psf.GetString("APP_VER");
}
return game;
}

View file

@ -80,8 +80,8 @@ public:
if (selected == &openSfoViewer) {
PSF psf;
if (psf.open(m_games[itemID].path + "/sce_sys/param.sfo", {})) {
int rows = psf.map_strings.size() + psf.map_integers.size();
if (psf.Open(std::filesystem::path(m_games[itemID].path) / "sce_sys" / "param.sfo")) {
int rows = psf.GetEntries().size();
QTableWidget* tableWidget = new QTableWidget(rows, 2);
tableWidget->setAttribute(Qt::WA_DeleteOnClose);
connect(widget->parent(), &QWidget::destroyed, tableWidget,
@ -90,23 +90,33 @@ public:
tableWidget->verticalHeader()->setVisible(false); // Hide vertical header
int row = 0;
for (const auto& pair : psf.map_strings) {
for (const auto& entry : psf.GetEntries()) {
QTableWidgetItem* keyItem =
new QTableWidgetItem(QString::fromStdString(pair.first));
QTableWidgetItem* valueItem =
new QTableWidgetItem(QString::fromStdString(pair.second));
new QTableWidgetItem(QString::fromStdString(entry.key));
QTableWidgetItem* valueItem;
switch (entry.param_fmt) {
case PSFEntryFmt::Binary: {
tableWidget->setItem(row, 0, keyItem);
tableWidget->setItem(row, 1, valueItem);
keyItem->setFlags(keyItem->flags() & ~Qt::ItemIsEditable);
valueItem->setFlags(valueItem->flags() & ~Qt::ItemIsEditable);
row++;
}
for (const auto& pair : psf.map_integers) {
QTableWidgetItem* keyItem =
new QTableWidgetItem(QString::fromStdString(pair.first));
QTableWidgetItem* valueItem = new QTableWidgetItem(
QString("0x").append(QString::number(pair.second, 16)));
const auto bin = *psf.GetBinary(entry.key);
std::string text;
text.reserve(bin.size() * 2);
for (const auto& c : bin) {
static constexpr char hex[] = "0123456789ABCDEF";
text.push_back(hex[c >> 4 & 0xF]);
text.push_back(hex[c & 0xF]);
}
valueItem = new QTableWidgetItem(QString::fromStdString(text));
} break;
case PSFEntryFmt::Text: {
auto text = *psf.GetString(entry.key);
valueItem = new QTableWidgetItem(QString::fromStdString(std::string{text}));
} break;
case PSFEntryFmt::Integer: {
auto integer = *psf.GetInteger(entry.key);
valueItem =
new QTableWidgetItem(QString("0x") + QString::number(integer, 16));
} break;
}
tableWidget->setItem(row, 0, keyItem);
tableWidget->setItem(row, 1, valueItem);

View file

@ -636,9 +636,9 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
QMessageBox msgBox;
msgBox.setWindowTitle(tr("PKG Extraction"));
psf.open("", pkg.sfo);
psf.Open(pkg.sfo);
std::string content_id = psf.GetString("CONTENT_ID");
std::string content_id{*psf.GetString("CONTENT_ID")};
std::string entitlement_label = Common::SplitString(content_id, '-')[2];
auto addon_extract_path = Common::FS::GetUserPath(Common::FS::PathType::AddonsDir) /
@ -647,9 +647,11 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
auto category = psf.GetString("CATEGORY");
if (pkgType.contains("PATCH")) {
QString pkg_app_version = QString::fromStdString(psf.GetString("APP_VER"));
psf.open(extract_path.string() + "/sce_sys/param.sfo", {});
QString game_app_version = QString::fromStdString(psf.GetString("APP_VER"));
QString pkg_app_version =
QString::fromStdString(std::string{*psf.GetString("APP_VER")});
psf.Open(extract_path / "sce_sys" / "param.sfo");
QString game_app_version =
QString::fromStdString(std::string{*psf.GetString("APP_VER")});
double appD = game_app_version.toDouble();
double pkgD = pkg_app_version.toDouble();
if (pkgD == appD) {

View file

@ -109,12 +109,12 @@ void PKGViewer::ProcessPKGInfo() {
path = std::filesystem::path(m_pkg_list[i].toStdWString());
#endif
package.Open(path);
psf.open("", package.sfo);
QString title_name = QString::fromStdString(psf.GetString("TITLE"));
QString title_id = QString::fromStdString(psf.GetString("TITLE_ID"));
QString app_type = game_list_util.GetAppType(psf.GetInteger("APP_TYPE"));
QString app_version = QString::fromStdString(psf.GetString("APP_VER"));
QString title_category = QString::fromStdString(psf.GetString("CATEGORY"));
psf.Open(package.sfo);
QString title_name = QString::fromStdString(std::string{*psf.GetString("TITLE")});
QString title_id = QString::fromStdString(std::string{*psf.GetString("TITLE_ID")});
QString app_type = game_list_util.GetAppType(*psf.GetInteger("APP_TYPE"));
QString app_version = QString::fromStdString(std::string{*psf.GetString("APP_VER")});
QString title_category = QString::fromStdString(std::string{*psf.GetString("CATEGORY")});
QString pkg_size = game_list_util.FormatSize(package.GetPkgHeader().pkg_size);
pkg_content_flag = package.GetPkgHeader().pkg_content_flags;
QString flagss = "";
@ -126,7 +126,7 @@ void PKGViewer::ProcessPKGInfo() {
}
}
u32 fw_int = psf.GetInteger("SYSTEM_VER");
u32 fw_int = *psf.GetInteger("SYSTEM_VER");
QString fw = QString::number(fw_int, 16);
QString fw_ = fw.length() > 7 ? QString::number(fw_int, 16).left(3).insert(2, '.')
: fw.left(3).insert(1, '.');

View file

@ -33,7 +33,6 @@ private:
PKGHeader pkgheader;
PKGEntry entry;
PSFHeader header;
PSFEntry psfentry;
char pkgTitleID[9];
std::vector<u8> pkg;
u64 pkgSize = 0;