Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 65 additions & 11 deletions src/data/FF7Save.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,29 @@ FF7SaveInfo::FORMAT FF7Save::fileDataFormat(QFile &file)
: QStringLiteral("Unknown"));
return FF7SaveInfo::FORMAT::UNKNOWN;
}
if ( (file_size == FF7SaveInfo::fileSize(FF7SaveInfo::FORMAT::PS4)) && file.peek(0x00B0 + FF7SaveInfo::fileIdentifier(FF7SaveInfo::FORMAT::PS4).length()).mid(0x00B0,FF7SaveInfo::get()->fileIdentifier(FF7SaveInfo::FORMAT::PS4).length()) == FF7SaveInfo::get()->fileIdentifier(FF7SaveInfo::FORMAT::PS4)) {
QTextStream(stdout)
<< "[FF7Save::loadFile] PS4 Save "
<< file.peek(0x00B0+FF7SaveInfo::get()->fileIdentifier(FF7SaveInfo::FORMAT::PS4).length()).mid(0x00B0,FF7SaveInfo::get()->fileIdentifier(FF7SaveInfo::FORMAT::PS4).length()).toHex( )
<< "\n";
QFile ps4binfile(QFileInfo(file).path() + "/" + QFileInfo(file).fileName() + ".bin");//QFileInfo(file).baseName()
if (!ps4binfile.open(QIODevice::ReadOnly)) {
QTextStream(stdout) << "[FF7Save::loadFile] PS4 BIN File error: missing file: " << QFileInfo(ps4binfile).absoluteFilePath();
return FF7SaveInfo::FORMAT::UNKNOWN;
} else {
QTextStream(stdout) << "[FF7Save::loadFile] PS4 BIN File loaded: " << QFileInfo(ps4binfile).absoluteFilePath() << "\n";
if(ps4binfile.size() == FF7SaveInfo::get()->fileSize(FF7SaveInfo::FORMAT::PS4BIN) && (ps4binfile.peek(FF7SaveInfo::fileHeaderSize(FF7SaveInfo::FORMAT::PS4BIN)) == FF7SaveInfo::fileIdentifier(FF7SaveInfo::FORMAT::PS4BIN))) {
auto ps4bin = ps4binfile.readAll();
m_ps4_iv = ps4bin.mid(0x10, 0x10);
m_ps4_key = ps4bin.mid(0x20, 0x20);
QTextStream(stdout)
<< "[FF7Save::loadFile] PS4 BIN File Size: " << FF7SaveInfo::get()->fileSize(FF7SaveInfo::FORMAT::PS4BIN) << "\n"
<< "[FF7Save::loadFile] PS4 BIN pfsSKKey IV: " << m_ps4_iv.toHex() << "\n"
<< "[FF7Save::loadFile] PS4 BIN pfsSKKey KEY: " << m_ps4_key.toHex() << "\n";
return FF7SaveInfo::FORMAT::PS4;
}
}
}
if ((file_size == FF7SaveInfo::fileSize(FF7SaveInfo::FORMAT::PSP)) && (file.peek(25)).startsWith(FF7SaveInfo::fileIdentifier(FF7SaveInfo::FORMAT::PSP)))
return FF7SaveInfo::FORMAT::PSP;
if ((file_size == FF7SaveInfo::fileSize(FF7SaveInfo::FORMAT::VGS)) && (file.peek(25)).startsWith(FF7SaveInfo::fileIdentifier(FF7SaveInfo::FORMAT::VGS)))
Expand Down Expand Up @@ -91,13 +114,28 @@ bool FF7Save::loadFile(const QString &fileName)
return false;

setFormat(fileFormat);
/*~~~~~~~~~~Start Load~~~~~~~~~~*/
setFileHeader(file.read(FF7SaveInfo::fileHeaderSize(fileFormat)));
for (int i = 0; i < FF7SaveInfo::slotCount(fileFormat); i++) {
setSlotHeader(i, file.read(FF7SaveInfo::slotHeaderSize(fileFormat)));
setSlotFF7Data(i, file.read(FF7SaveInfo::slotSize()));
setSlotFooter(i, file.read(FF7SaveInfo::slotFooterSize(fileFormat)));


if(fileFormat == FF7SaveInfo::FORMAT::PS4) {
qDebug() << "Trying to Decrypt";
QFile ofile("outdata.dat");
ofile.open(QFile::WriteOnly);
ofile.write(decryptPS4Save(file.readAll()));
for (int i = 0; i < FF7SaveInfo::slotCount(fileFormat); i++) {
setSlotHeader(i, QByteArray());
setSlotFF7Data(i, decryptPS4Save(file.readAll()));
setSlotFooter(i, QByteArray());
}
} else {
/*~~~~~~~~~~Start Load~~~~~~~~~~*/
setFileHeader(file.read(FF7SaveInfo::fileHeaderSize(fileFormat)));
for (int i = 0; i < FF7SaveInfo::slotCount(fileFormat); i++) {
setSlotHeader(i, file.read(FF7SaveInfo::slotHeaderSize(fileFormat)));
setSlotFF7Data(i, file.read(FF7SaveInfo::slotSize()));
setSlotFooter(i, file.read(FF7SaveInfo::slotFooterSize(fileFormat)));
}
}

/*~~~~~~~End Load~~~~~~~~~~~~~~*/
if (FF7SaveInfo::isTypePC(fileFormat)) {
for (int i = 0; i < 15; i++) {
Expand Down Expand Up @@ -913,7 +951,8 @@ char FF7Save::psx_block_type(int s)
case FF7SaveInfo::FORMAT::PC:
case FF7SaveInfo::FORMAT::SWITCH:
case FF7SaveInfo::FORMAT::PSX:
case FF7SaveInfo::FORMAT::PS3: return 0x00;
case FF7SaveInfo::FORMAT::PS3:
case FF7SaveInfo::FORMAT::PS4: return 0x00;
case FF7SaveInfo::FORMAT::PGE: return _fileHeader.at(0);
default:
int index = 128 + (128 * s);
Expand All @@ -930,7 +969,8 @@ void FF7Save::setPsx_block_type(int s, char block_type)
case FF7SaveInfo::FORMAT::PC:
case FF7SaveInfo::FORMAT::SWITCH:
case FF7SaveInfo::FORMAT::PSX:
case FF7SaveInfo::FORMAT::PS3: return;
case FF7SaveInfo::FORMAT::PS3:
case FF7SaveInfo::FORMAT::PS4: return;
case FF7SaveInfo::FORMAT::PGE: _fileHeader.replace(0, 1, QByteArray(1, block_type)); break;
default:
int index = 128 + (128 * s);
Expand All @@ -950,7 +990,8 @@ void FF7Save::setPsx_block_next(int s, int next)
case FF7SaveInfo::FORMAT::PC:
case FF7SaveInfo::FORMAT::SWITCH:
case FF7SaveInfo::FORMAT::PSX:
case FF7SaveInfo::FORMAT::PS3: return;
case FF7SaveInfo::FORMAT::PS3:
case FF7SaveInfo::FORMAT::PS4: return;
case FF7SaveInfo::FORMAT::PGE: _fileHeader.replace(8, 1, QByteArray(1, next)); break;
default:
int index = 128 + (128 * s);
Expand All @@ -967,7 +1008,8 @@ quint8 FF7Save::psx_block_next(int s)
case FF7SaveInfo::FORMAT::PC:
case FF7SaveInfo::FORMAT::SWITCH:
case FF7SaveInfo::FORMAT::PSX:
case FF7SaveInfo::FORMAT::PS3: return 0x00;
case FF7SaveInfo::FORMAT::PS3:
case FF7SaveInfo::FORMAT::PS4: return 0x00;
case FF7SaveInfo::FORMAT::PGE: return quint8(_fileHeader.at(0x08));
default:
int index = 128 + (128 * s);
Expand All @@ -984,7 +1026,8 @@ void FF7Save::setPsx_block_size(int s, int blockSize)
case FF7SaveInfo::FORMAT::PC:
case FF7SaveInfo::FORMAT::SWITCH:
case FF7SaveInfo::FORMAT::PSX:
case FF7SaveInfo::FORMAT::PS3: return;
case FF7SaveInfo::FORMAT::PS3:
case FF7SaveInfo::FORMAT::PS4: return;
default: break;
}

Expand All @@ -1007,6 +1050,7 @@ quint8 FF7Save::psx_block_size(int s)
switch (fileFormat) {
case FF7SaveInfo::FORMAT::UNKNOWN:
case FF7SaveInfo::FORMAT::PC:
case FF7SaveInfo::FORMAT::PS4:
case FF7SaveInfo::FORMAT::SWITCH: return 1;
case FF7SaveInfo::FORMAT::PSX: return quint8(QFile(fileName()).size() / FF7SaveInfo::fileSize(FF7SaveInfo::FORMAT::PSX));
case FF7SaveInfo::FORMAT::PS3: return quint8((QFile(fileName()).size() - 0x84) / FF7SaveInfo::fileSize(FF7SaveInfo::FORMAT::PSX));
Expand Down Expand Up @@ -2747,6 +2791,16 @@ bool FF7Save::fixMetaData(QString fileName, QString UserID)
return 1;
}

QByteArray FF7Save::decryptPS4Save(QByteArray in)
{
QByteArray buffer = in;
struct AES_ctx ctx;
AES_init_ctx_iv(&ctx, reinterpret_cast<uint8_t*>(m_ps4_key.data()), reinterpret_cast<uint8_t*>(m_ps4_iv.data()));
AES_CBC_decrypt_buffer(&ctx, reinterpret_cast<uint8_t*>(buffer.data()), 256);
qDebug() << "Decrypted Size" << buffer.size();
return buffer;

}
QByteArray FF7Save::generatePsSaveSignature(QByteArray data, QByteArray keySeed)
{
FF7SaveInfo::FORMAT saveFormat = format();
Expand Down
5 changes: 4 additions & 1 deletion src/data/FF7Save.h
Original file line number Diff line number Diff line change
Expand Up @@ -1020,6 +1020,8 @@ class FF7TKDATA_EXPORT FF7Save: public QObject
*/
QString md5sum(QString fileName, QString UserID);


QByteArray decryptPS4Save(QByteArray in);
QString fileblock(const QString &fileName);
QString filetimestamp(QString fileName);
void checksumSlots();
Expand All @@ -1042,10 +1044,11 @@ class FF7TKDATA_EXPORT FF7Save: public QObject
bool fileHasChanged;
QString buffer_region; // hold the buffers region data.
QList<QString> SG_Region_String;
QByteArray m_ps4_iv;
QByteArray m_ps4_key;
QString filename;//opened file
QVector< SubContainer > parseXML(const QString &fileName, const QString &metadataPath, const QString &UserID);
QVector< SubContainer > createMetadata(const QString &fileName, const QString &UserID);

inline static const auto allDigetRegEx = QRegularExpression(QStringLiteral("^\\d+$"));
inline static const QString invalidRegion = QStringLiteral("\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000");
};
30 changes: 26 additions & 4 deletions src/data/FF7SaveInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ int FF7SaveInfo::fileSize(FF7SaveInfo::FORMAT format)
case FORMAT::VMC: return get()->d->VMC_FILE_SIZE;
case FORMAT::PSP: return get()->d->PSP_FILE_SIZE;
case FORMAT::PS3: return get()->d->PS3_FILE_SIZE;
case FORMAT::PS4: return get()->d->PS4_FILE_SIZE;
case FORMAT::PS4BIN: return get()->d->PS4_BINFILE_SIZE;
case FORMAT::DEX: return get()->d->DEX_FILE_SIZE;
case FORMAT::VGS: return get()->d->VGS_FILE_SIZE;
case FORMAT::SWITCH: return get()->d->SWITCH_FILE_SIZE;
Expand All @@ -46,6 +48,8 @@ int FF7SaveInfo::fileHeaderSize(FF7SaveInfo::FORMAT format)
case FORMAT::VMC: return get()->d->VMC_FILE_HEADER_SIZE;
case FORMAT::PSP: return get()->d->PSP_FILE_HEADER_SIZE;
case FORMAT::PS3: return get()->d->PS3_FILE_HEADER_SIZE;
case FORMAT::PS4: return get()->d->PS4_FILE_HEADER_SIZE;
case FORMAT::PS4BIN: return get()->d->PS4_BINFILE_FILE_ID_SIZE;
case FORMAT::DEX: return get()->d->DEX_FILE_HEADER_SIZE;
case FORMAT::VGS: return get()->d->VGS_FILE_HEADER_SIZE;
case FORMAT::SWITCH: return get()->d->SWITCH_FILE_HEADER_SIZE;
Expand All @@ -62,6 +66,7 @@ int FF7SaveInfo::slotHeaderSize(FF7SaveInfo::FORMAT format)
case FORMAT::VMC:
case FORMAT::PSP:
case FORMAT::PS3:
case FORMAT::PS4:
case FORMAT::DEX:
case FORMAT::PGE:
case FORMAT::PDA:
Expand All @@ -77,6 +82,7 @@ int FF7SaveInfo::slotFooterSize(FF7SaveInfo::FORMAT format)
case FORMAT::VMC:
case FORMAT::PSP:
case FORMAT::PS3:
case FORMAT::PS4:
case FORMAT::DEX:
case FORMAT::PGE:
case FORMAT::PDA:
Expand All @@ -91,7 +97,8 @@ int FF7SaveInfo::slotCount(FF7SaveInfo::FORMAT format)
case FORMAT::PDA:
case FORMAT::PGE:
case FORMAT::PSX:
case FORMAT::PS3: return 1;
case FORMAT::PS3:
case FORMAT::PS4: return 1;
case FORMAT::VMC:
case FORMAT::PSP:
case FORMAT::DEX:
Expand All @@ -110,6 +117,8 @@ QByteArray FF7SaveInfo::fileIdentifier(FF7SaveInfo::FORMAT format)
case FORMAT::VMC: return get()->d->VMC_FILE_ID;
case FORMAT::PSP: return get()->d->PSP_FILE_ID;
case FORMAT::PS3: return get()->d->PS3_FILE_ID;
case FORMAT::PS4: return get()->d->PS4_FILE_ID;
case FORMAT::PS4BIN: return get()->d->PS4_BINFILE_FILE_ID;
// case FORMAT::DEX: return get()->d->DEX_FILE_ID;
case FORMAT::VGS: return get()->d->VGS_FILE_ID;
case FORMAT::SWITCH: return get()->d->SWITCH_FILE_ID;
Expand All @@ -127,6 +136,7 @@ QByteArray FF7SaveInfo::fileHeader(FF7SaveInfo::FORMAT format)
case FORMAT::VMC: return QByteArray(fileIdentifier(format)).append(fileHeaderSize(format) - fileIdentifier(format).length(), 0x00);
case FORMAT::PSP: return get()->d->PSP_FILE_HEADER;
case FORMAT::PS3: return get()->d->PS3_FILE_HEADER;
case FORMAT::PS4: return get()->d->PS4_FILE_HEADER;
default: return QByteArray();
}
}
Expand All @@ -140,6 +150,7 @@ QByteArray FF7SaveInfo::slotHeader(FF7SaveInfo::FORMAT format, int slot)
case FORMAT::PSX:
case FORMAT::PSP:
case FORMAT::PS3:
case FORMAT::PS4:
case FORMAT::DEX:
case FORMAT::VGS:
case FORMAT::VMC: return QByteArray(get()->d->PSX_SLOT_HEADER.at(slot)).append(256, 0x00);
Expand All @@ -155,6 +166,7 @@ QByteArray FF7SaveInfo::slotFooter(FF7SaveInfo::FORMAT format)
case FORMAT::PSX:
case FORMAT::PSP:
case FORMAT::PS3:
case FORMAT::PS4:
case FORMAT::DEX:
case FORMAT::VGS:
case FORMAT::VMC: return QByteArray(get()->d->PSX_SLOT_FOOTER_SIZE, 0x00);
Expand All @@ -167,6 +179,7 @@ QByteArray FF7SaveInfo::signingKey(FF7SaveInfo::FORMAT format)
switch (format) {
case FORMAT::PSP:
case FORMAT::PS3: return get()->d->PS_SIGNING_KEY;
case FORMAT::PS4: return get()->d->PS4_SIGNING_KEY;
default: return QByteArray();
}
}
Expand All @@ -187,6 +200,7 @@ QByteArray FF7SaveInfo::signingIV(FF7SaveInfo::FORMAT format)
switch (format) {
case FORMAT::PSP:
case FORMAT::PS3: return get()->d->PS_SIGNING_IV;
case FORMAT::PS4: return get()->d->PS4_SIGNING_IV;
default: return QByteArray();
}
}
Expand All @@ -196,6 +210,7 @@ int FF7SaveInfo::fileSeedOffset(FF7SaveInfo::FORMAT format)
switch (format) {
case FORMAT::PSP: return get()->d->PSP_SEED_OFFSET;
case FORMAT::PS3: return get()->d->PS3_SEED_OFFSET;
case FORMAT::PS4: return get()->d->PS4_SEED_OFFSET;
default: return -1;
}
}
Expand All @@ -205,6 +220,7 @@ int FF7SaveInfo::fileSignatureOffset(FF7SaveInfo::FORMAT format)
switch (format) {
case FORMAT::PSP: return get()->d->PSP_SIGNATURE_OFFSET;
case FORMAT::PS3: return get()->d->PS3_SIGNATURE_OFFSET;
case FORMAT::PS4: return get()->d->PS4_SIGNATURE_OFFSET;
default: return -1;
}
}
Expand All @@ -214,6 +230,7 @@ int FF7SaveInfo::fileSignatureSize(FF7SaveInfo::FORMAT format)
switch (format) {
case FORMAT::PSP:
case FORMAT::PS3: return get()->d->PS_SIGNATURE_SIZE;
case FORMAT::PS4: return get()->d->PS4_SIGNATURE_SIZE;
default: return 0;
}
}
Expand All @@ -230,6 +247,7 @@ QRegularExpression FF7SaveInfo::validNames(FF7SaveInfo::FORMAT format)
case FORMAT::PSX: return get()->d->PSX_VALID_NAME_REGEX;
case FORMAT::PSP: return get()->d->PSP_VALID_NAME_REGEX;
case FORMAT::PS3: return get()->d->PS3_VALID_NAME_REGEX;
case FORMAT::PS4: return get()->d->PS4_VALID_NAME_REGEX;
case FORMAT::DEX: return get()->d->DEX_VALID_NAME_REGEX;
case FORMAT::VGS: return get()->d->VGS_VALID_NAME_REGEX;
case FORMAT::VMC: return get()->d->VMC_VALID_NAME_REGEX;
Expand All @@ -247,6 +265,7 @@ QString FF7SaveInfo::typeDescription(FF7SaveInfo::FORMAT format)
case FORMAT::PSX: return tr(get()->d->PSX_FILE_DESCRIPTION.toUtf8());
case FORMAT::PSP: return tr(get()->d->PSP_FILE_DESCRIPTION.toUtf8());
case FORMAT::PS3: return tr(get()->d->PS3_FILE_DESCRIPTION.toUtf8());
case FORMAT::PS4: return tr(get()->d->PS4_FILE_DESCRIPTION.toUtf8());
case FORMAT::DEX: return tr(get()->d->DEX_FILE_DESCRIPTION.toUtf8());
case FORMAT::VGS: return tr(get()->d->VGS_FILE_DESCRIPTION.toUtf8());
case FORMAT::VMC: return tr(get()->d->VMC_FILE_DESCRIPTION.toUtf8());
Expand All @@ -264,6 +283,7 @@ QStringList FF7SaveInfo::typeExtension(FF7SaveInfo::FORMAT format)
case FORMAT::PSX: return get()->d->PSX_VALID_EXTENSIONS;
case FORMAT::PSP: return get()->d->PSP_VALID_EXTENSIONS;
case FORMAT::PS3: return get()->d->PS3_VALID_EXTENSIONS;
case FORMAT::PS4: return get()->d->PS4_VALID_EXTENSIONS;
case FORMAT::DEX: return get()->d->DEX_VALID_EXTENSIONS;
case FORMAT::VGS: return get()->d->VGS_VALID_EXTENSIONS;
case FORMAT::VMC: return get()->d->VMC_VALID_EXTENSIONS;
Expand All @@ -284,25 +304,27 @@ QString FF7SaveInfo::typeFilter(FF7SaveInfo::FORMAT format)
QString FF7SaveInfo::knownTypesFilter()
{
QString space = QStringLiteral(" ");
QString allTypes = QStringLiteral("%1 %2 %3 %4 %5 %6 %7 %8 %9 %10")
QString allTypes = QStringLiteral("%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11")
.arg(get()->d->PC_VALID_EXTENSIONS.join(space)
, get()->d->PSX_VALID_EXTENSIONS.join(space)
, get()->d->PSP_VALID_EXTENSIONS.join(space)
, get()->d->PS3_VALID_EXTENSIONS.join(space)
, get()->d->PS4_VALID_EXTENSIONS.join(space)
, get()->d->DEX_VALID_EXTENSIONS.join(space)
, get()->d->VGS_VALID_EXTENSIONS.join(space)
, get()->d->VMC_VALID_EXTENSIONS.join(space)
, get()->d->SWITCH_VALID_EXTENSIONS.join(space)
, get()->d->PGE_VALID_EXTENSIONS.join(space)
, get()->d->PDA_VALID_EXTENSIONS.join(space));

return QStringLiteral("%1;;%2;;%3;;%4;;%5;;%6;;%7;;%8;;%9;;%10;;%11;;%12")
return QStringLiteral("%1;;%2;;%3;;%4;;%5;;%6;;%7;;%8;;%9;;%10;;%11;;%12;;%13")
.arg(tr("Known FF7 Save Types (%1)").arg(allTypes)
, typeFilter(FORMAT::PC)
, typeFilter(FORMAT::SWITCH)
, typeFilter(FORMAT::VMC)
, typeFilter(FORMAT::PSX)
, typeFilter(FORMAT::PS3)
, typeFilter(FORMAT::PS4)
, typeFilter(FORMAT::PSP)
, typeFilter(FORMAT::DEX)
, typeFilter(FORMAT::VGS)
Expand All @@ -315,6 +337,7 @@ bool FF7SaveInfo::isTypePC(FF7SaveInfo::FORMAT format)
{
switch(format) {
case FORMAT::SWITCH:
case FORMAT::PS4:
case FORMAT::PC: return true;
default: return false;
};
Expand Down Expand Up @@ -368,4 +391,3 @@ QByteArray FF7SaveInfo::defaultSaveData()
{
return get()->d->DEFAULT_SAVE;
}

Loading
Loading