improved RDR 2 support, libragephoto upstream

This commit is contained in:
Syping 2023-04-05 22:26:57 +02:00
parent a10d259db1
commit 6e38894bcc
5 changed files with 43 additions and 85 deletions

View file

@ -277,13 +277,13 @@ void ProfileInterface::directoryChanged(const QString &path)
const QStringList files = dir.entryList(QDir::Files); const QStringList files = dir.entryList(QDir::Files);
for (const QString &fileName : files) { for (const QString &fileName : files) {
if (fileName.startsWith("SGTA5") && !fileName.endsWith(".bak")) { if ((fileName.startsWith("SGTA5") || fileName.startsWith("SRDR3")) && !fileName.endsWith(".bak")) {
t_savegameFiles << fileName; t_savegameFiles << fileName;
if (!savegameFiles.contains(fileName)) { if (!savegameFiles.contains(fileName)) {
n_savegameFiles << fileName; n_savegameFiles << fileName;
} }
} }
if (fileName.startsWith("PGTA5") && !fileName.endsWith(".bak")) { if ((fileName.startsWith("PGTA5") || fileName.startsWith("PRDR3")) && !fileName.endsWith(".bak")) {
t_snapmaticPics << fileName; t_snapmaticPics << fileName;
if (fileName.endsWith(".hidden")) { if (fileName.endsWith(".hidden")) {
const QString originalFileName = fileName.left(fileName.length() - 7); const QString originalFileName = fileName.left(fileName.length() - 7);
@ -559,18 +559,18 @@ fileDialogPreOpen: //Work?
for (const QByteArray &imageFormat : QImageReader::supportedImageFormats()) { for (const QByteArray &imageFormat : QImageReader::supportedImageFormats()) {
imageFormatsStr += QString("*.") % QString::fromUtf8(imageFormat).toLower() % " "; imageFormatsStr += QString("*.") % QString::fromUtf8(imageFormat).toLower() % " ";
} }
QString importableFormatsStr = QString("*.g5e SGTA* PGTA*"); QString importableFormatsStr = QString("*.g5e SGTA5* PGTA5*");
if (!imageFormatsStr.trimmed().isEmpty()) { if (!imageFormatsStr.trimmed().isEmpty()) {
importableFormatsStr = QString("*.g5e%1SGTA* PGTA*").arg(imageFormatsStr); importableFormatsStr = QString("*.g5e%1SGTA5* PGTA5*").arg(imageFormatsStr);
} }
QStringList filters; QStringList filters;
filters << tr("Importable files (%1)").arg(importableFormatsStr); filters << tr("All importable files (%1)").arg(importableFormatsStr);
filters << tr("GTA V Export (*.g5e)"); filters << tr("GTA V Export (%1)").arg("*.g5e");
filters << tr("Savegames files (SGTA*)"); filters << tr("GTA V Savegames files (%1)").arg("SGTA5*");
filters << tr("Snapmatic pictures (PGTA*)"); filters << tr("GTA V Snapmatic files (%1)").arg("PGTA5*");
filters << tr("All image files (%1)").arg(imageFormatsStr.trimmed()); filters << tr("All image files (%1)").arg(imageFormatsStr.trimmed());
filters << tr("All files (**)"); filters << tr("All files (%1)").arg("**");
fileDialog.setNameFilters(filters); fileDialog.setNameFilters(filters);
QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls()); QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls());
@ -796,15 +796,8 @@ bool ProfileInterface::importFile(QString selectedFile, QDateTime importDateTime
cEnough++; cEnough++;
} }
spJson.createdDateTime = importDateTime; spJson.createdDateTime = importDateTime;
#if QT_VERSION >= 0x060000 qint64 timestamp = spJson.createdDateTime.toSecsSinceEpoch();
quint64 timestamp = spJson.createdDateTime.toSecsSinceEpoch(); spJson.createdTimestamp = timestamp;
if (timestamp > UINT32_MAX) {
timestamp = UINT32_MAX;
}
spJson.createdTimestamp = (quint32)timestamp;
#else
spJson.createdTimestamp = spJson.createdDateTime.toTime_t();
#endif
picture->setSnapmaticProperties(spJson); picture->setSnapmaticProperties(spJson);
const QString picFileName = QString("PGTA5%1").arg(QString::number(spJson.uid)); const QString picFileName = QString("PGTA5%1").arg(QString::number(spJson.uid));
picture->setPicFileName(picFileName); picture->setPicFileName(picFileName);
@ -854,15 +847,8 @@ bool ProfileInterface::importFile(QString selectedFile, QDateTime importDateTime
cEnough++; cEnough++;
} }
spJson.createdDateTime = importDateTime; spJson.createdDateTime = importDateTime;
#if QT_VERSION >= 0x060000 qint64 timestamp = spJson.createdDateTime.toSecsSinceEpoch();
quint64 timestamp = spJson.createdDateTime.toSecsSinceEpoch(); spJson.createdTimestamp = timestamp;
if (timestamp > UINT32_MAX) {
timestamp = UINT32_MAX;
}
spJson.createdTimestamp = (quint32)timestamp;
#else
spJson.createdTimestamp = spJson.createdDateTime.toTime_t();
#endif
picture->setSnapmaticProperties(spJson); picture->setSnapmaticProperties(spJson);
const QString picFileName = QString("PGTA5%1").arg(QString::number(spJson.uid)); const QString picFileName = QString("PGTA5%1").arg(QString::number(spJson.uid));
picture->setPicFileName(picFileName); picture->setPicFileName(picFileName);
@ -1124,15 +1110,15 @@ bool ProfileInterface::importSnapmaticPicture(SnapmaticPicture *picture, bool wa
{ {
QString picFileName = picture->getPictureFileName(); QString picFileName = picture->getPictureFileName();
QString adjustedFileName = picture->getOriginalPictureFileName(); QString adjustedFileName = picture->getOriginalPictureFileName();
if (!picFileName.startsWith("PGTA5")) { if (!picFileName.startsWith("PGTA5") && !picFileName.startsWith("PRDR3")) {
if (warn) if (warn)
QMessageBox::warning(this, tr("Import..."), tr("Failed to import the Snapmatic picture, file not begin with PGTA or end with .g5e")); QMessageBox::warning(this, tr("Import..."), tr("Photo import failed! It is not a GTA V or RDR 2 compatible photo"));
return false; return false;
} }
else if (QFile::exists(profileFolder % "/" % adjustedFileName) || QFile::exists(profileFolder % "/" % adjustedFileName % ".hidden")) { else if (QFile::exists(profileFolder % "/" % adjustedFileName) || QFile::exists(profileFolder % "/" % adjustedFileName % ".hidden")) {
SnapmaticProperties snapmaticProperties = picture->getSnapmaticProperties(); SnapmaticProperties snapmaticProperties = picture->getSnapmaticProperties();
if (warn) { if (warn) {
int uchoice = QMessageBox::question(this, tr("Import..."), tr("A Snapmatic picture already exists with the uid %1, you want assign your import a new uid and timestamp?").arg(QString::number(snapmaticProperties.uid)), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); int uchoice = QMessageBox::question(this, tr("Import..."), tr("A Photo already exists with the uid %1, you want assign your import a new uid and timestamp?").arg(QString::number(snapmaticProperties.uid)), QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
if (uchoice == QMessageBox::Yes) { if (uchoice == QMessageBox::Yes) {
// Update Snapmatic uid // Update Snapmatic uid
snapmaticProperties.uid = getRandomUid(); snapmaticProperties.uid = getRandomUid();
@ -1177,15 +1163,8 @@ bool ProfileInterface::importSnapmaticPicture(SnapmaticPicture *picture, bool wa
// Update Snapmatic uid // Update Snapmatic uid
snapmaticProperties.uid = getRandomUid(); snapmaticProperties.uid = getRandomUid();
snapmaticProperties.createdDateTime = QDateTime::currentDateTime(); snapmaticProperties.createdDateTime = QDateTime::currentDateTime();
#if QT_VERSION >= 0x060000 qint64 timestamp = snapmaticProperties.createdDateTime.toSecsSinceEpoch();
quint64 timestamp = snapmaticProperties.createdDateTime.toSecsSinceEpoch(); snapmaticProperties.createdTimestamp = timestamp;
if (timestamp > UINT32_MAX) {
timestamp = UINT32_MAX;
}
snapmaticProperties.createdTimestamp = (quint32)timestamp;
#else
snapmaticProperties.createdTimestamp = snapmaticProperties.createdDateTime.toTime_t();
#endif
bool fExists = QFile::exists(profileFolder % "/PGTA5" % QString::number(snapmaticProperties.uid)); bool fExists = QFile::exists(profileFolder % "/PGTA5" % QString::number(snapmaticProperties.uid));
bool fExistsBackup = QFile::exists(profileFolder % "/PGTA5" % QString::number(snapmaticProperties.uid) % ".bak"); bool fExistsBackup = QFile::exists(profileFolder % "/PGTA5" % QString::number(snapmaticProperties.uid) % ".bak");
bool fExistsHidden = QFile::exists(profileFolder % "/PGTA5" % QString::number(snapmaticProperties.uid) % ".hidden"); bool fExistsHidden = QFile::exists(profileFolder % "/PGTA5" % QString::number(snapmaticProperties.uid) % ".hidden");
@ -1219,7 +1198,7 @@ bool ProfileInterface::importSnapmaticPicture(SnapmaticPicture *picture, bool wa
} }
else { else {
if (warn) if (warn)
QMessageBox::warning(this, tr("Import..."), tr("Failed to import the Snapmatic picture, can't copy the file into profile")); QMessageBox::warning(this, tr("Import..."), tr("Photo import failed! Can not copy the file in the profile"));
return false; return false;
} }
} }
@ -1255,13 +1234,13 @@ bool ProfileInterface::importSavegameData(SavegameData *savegame, QString sgdPat
} }
else { else {
if (warn) if (warn)
QMessageBox::warning(this, tr("Import..."), tr("Failed to import the Savegame, can't copy the file into profile")); QMessageBox::warning(this, tr("Import..."), tr("Savegame import failed! Can not copy the file in the profile"));
return false; return false;
} }
} }
else { else {
if (warn) if (warn)
QMessageBox::warning(this, tr("Import..."), tr("Failed to import the Savegame, no Savegame slot is left")); QMessageBox::warning(this, tr("Import..."), tr("Savegame import failed! No Savegame slot is available"));
return false; return false;
} }
} }

View file

@ -45,40 +45,18 @@ void ProfileLoader::run()
QVector<QString> savegameFiles; QVector<QString> savegameFiles;
QVector<QString> snapmaticPics; QVector<QString> snapmaticPics;
#ifdef Q_OS_WIN
QDir dir(profileFolder); QDir dir(profileFolder);
const QStringList files = dir.entryList(QDir::Files); const QStringList files = dir.entryList(QDir::Files);
for (const QString &fileName : files) { for (const QString &fileName : files) {
if (fileName.startsWith("SGTA5") && !fileName.endsWith(".bak")) { if ((fileName.startsWith("SGTA5") || fileName.startsWith("SRDR3")) && !fileName.endsWith(".bak")) {
savegameFiles << fileName; savegameFiles << fileName;
maximumV++; maximumV++;
} }
if (fileName.startsWith("PGTA5") && !fileName.endsWith(".bak")) { if ((fileName.startsWith("PGTA5") || fileName.startsWith("PRDR3")) && !fileName.endsWith(".bak")) {
snapmaticPics << fileName; snapmaticPics << fileName;
maximumV++; maximumV++;
} }
} }
#else
DIR *dirp = opendir(profileFolder.toUtf8().constData());
struct dirent *dp;
while ((dp = readdir(dirp)) != 0) {
const QString fileName = QString::fromUtf8(dp->d_name);
const QString filePath = profileFolder % "/" % fileName;
struct stat fileStat;
stat(filePath.toUtf8().constData(), &fileStat);
if (S_ISREG(fileStat.st_mode) != 0) {
if (fileName.startsWith("SGTA5") && !fileName.endsWith(".bak")) {
savegameFiles << fileName;
maximumV++;
}
if (fileName.startsWith("PGTA5") && !fileName.endsWith(".bak")) {
snapmaticPics << fileName;
maximumV++;
}
}
}
closedir(dirp);
#endif
// Directory successfully scanned // Directory successfully scanned
emit directoryScanned(savegameFiles, snapmaticPics); emit directoryScanned(savegameFiles, snapmaticPics);

View file

@ -1,6 +1,6 @@
/***************************************************************************** /*****************************************************************************
* gta5view Grand Theft Auto V Profile Viewer * gta5view Grand Theft Auto V Profile Viewer
* Copyright (C) 2016-2017 Syping * Copyright (C) 2016-2023 Syping
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -24,7 +24,8 @@
#include <QFile> #include <QFile>
#define savegameHeaderLength 260 #define savegameHeaderLength 260
#define verificationValue QByteArray::fromHex("00000001") #define verificationValue_GTA5 QByteArray::fromHex("00000001")
#define verificationValue_RDR2 QByteArray::fromHex("00000004")
SavegameData::SavegameData(const QString &fileName, QObject *parent) : QObject(parent), savegameFileName(fileName) SavegameData::SavegameData(const QString &fileName, QObject *parent) : QObject(parent), savegameFileName(fileName)
{ {
@ -57,14 +58,11 @@ bool SavegameData::readingSavegame()
return false; return false;
} }
QByteArray savegameHeaderLine = saveFile->read(savegameHeaderLength); QByteArray savegameHeaderLine = saveFile->read(savegameHeaderLength);
if (savegameHeaderLine.left(4) == verificationValue) if (savegameHeaderLine.startsWith(verificationValue_GTA5) || savegameHeaderLine.startsWith(verificationValue_RDR2)) {
{
savegameStr = getSavegameDataString(savegameHeaderLine); savegameStr = getSavegameDataString(savegameHeaderLine);
if (savegameStr.length() >= 1) if (savegameStr.length() >= 1)
{
savegameOk = true; savegameOk = true;
} }
}
saveFile->close(); saveFile->close();
saveFile->deleteLater(); saveFile->deleteLater();
delete saveFile; delete saveFile;
@ -74,7 +72,12 @@ bool SavegameData::readingSavegame()
QString SavegameData::getSavegameDataString(const QByteArray &savegameHeader) QString SavegameData::getSavegameDataString(const QByteArray &savegameHeader)
{ {
QByteArray savegameBytes = savegameHeader.left(savegameHeaderLength); QByteArray savegameBytes = savegameHeader.left(savegameHeaderLength);
QList<QByteArray> savegameBytesList = savegameBytes.split(char(0x01)); char split_byte = 0x00;
if (savegameHeader.startsWith(verificationValue_GTA5))
split_byte = 0x01;
else if (savegameHeader.startsWith(verificationValue_RDR2))
split_byte = 0x04;
QList<QByteArray> savegameBytesList = savegameBytes.split(split_byte);
savegameBytes = savegameBytesList.at(1); savegameBytes = savegameBytesList.at(1);
savegameBytesList.clear(); savegameBytesList.clear();
return SnapmaticPicture::parseTitleString(savegameBytes); return SnapmaticPicture::parseTitleString(savegameBytes);
@ -82,16 +85,13 @@ QString SavegameData::getSavegameDataString(const QByteArray &savegameHeader)
bool SavegameData::readingSavegameFromFile(const QString &fileName) bool SavegameData::readingSavegameFromFile(const QString &fileName)
{ {
if (fileName != "") if (fileName != "") {
{
savegameFileName = fileName; savegameFileName = fileName;
return readingSavegame(); return readingSavegame();
} }
else else
{
return false; return false;
} }
}
bool SavegameData::isSavegameOk() bool SavegameData::isSavegameOk()
{ {

View file

@ -564,11 +564,12 @@ fileDialogPreOpen:
fileDialog.setWindowTitle(tr("Open File...")); fileDialog.setWindowTitle(tr("Open File..."));
QStringList filters; QStringList filters;
filters << ProfileInterface::tr("All profile files (*.g5e SGTA* PGTA*)"); filters << ProfileInterface::tr("All profile files (%1)").arg("*.g5e SGTA5* PGTA5* PRDR3*");
filters << ProfileInterface::tr("GTA V Export (*.g5e)"); filters << ProfileInterface::tr("GTA V Export (%1)").arg("*.g5e");
filters << ProfileInterface::tr("Savegames files (SGTA*)"); filters << ProfileInterface::tr("GTA V Savegames files (%1)").arg("SGTA5*");
filters << ProfileInterface::tr("Snapmatic pictures (PGTA*)"); filters << ProfileInterface::tr("GTA V Snapmatic files (%1)").arg("PGTA5*");
filters << ProfileInterface::tr("All files (**)"); filters << ProfileInterface::tr("RDR 2 Photo files (%1)").arg("PRDR3*");
filters << ProfileInterface::tr("All files (%1)").arg("**");
fileDialog.setNameFilters(filters); fileDialog.setNameFilters(filters);
QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls()); QList<QUrl> sidebarUrls = SidebarGenerator::generateSidebarUrls(fileDialog.sidebarUrls());
@ -603,7 +604,7 @@ bool UserInterface::openFile(QString selectedFile, bool warn)
} }
else { else {
if (warn) if (warn)
QMessageBox::warning(this, tr("Open File"), ProfileInterface::tr("Failed to read Snapmatic picture")); QMessageBox::warning(this, tr("Open File"), ProfileInterface::tr("Failed to read Photo file"));
delete picture; delete picture;
return false; return false;
} }
@ -641,7 +642,7 @@ bool UserInterface::openFile(QString selectedFile, bool warn)
delete savegame; delete savegame;
delete picture; delete picture;
if (warn) if (warn)
QMessageBox::warning(this, tr("Open File"), tr("Can't open %1 because of not valid file format").arg("\""+selectedFileName+"\"")); QMessageBox::warning(this, tr("Open File"), tr("Can not open %1 because file format is not valid").arg("\""+selectedFileName+"\""));
return false; return false;
} }
} }

@ -1 +1 @@
Subproject commit 302be665e2bdd6fb00628ad6310b161dcf8c834d Subproject commit 933918454f16af118a3cb9e1359a00bca589d7e7