From f8eb08a468b6d047e85ee7ff983eb3afd672af1d Mon Sep 17 00:00:00 2001 From: vegetass4 Date: Sat, 27 Jun 2020 17:34:23 -0300 Subject: [PATCH] Initial PS4 file support First phase PS4 compatibility --- src/data/FF7Save.cpp | 39 +++++++-- src/data/FF7Save.h | 2 + src/data/FF7SaveInfo.cpp | 184 ++++++++++++++++++++++----------------- src/data/FF7SaveInfo.h | 50 +++++++++++ translations/ff7tk_de.ts | 4 + translations/ff7tk_en.ts | 4 + translations/ff7tk_es.ts | 4 + translations/ff7tk_fr.ts | 4 + translations/ff7tk_it.ts | 4 + translations/ff7tk_ja.ts | 4 + translations/ff7tk_pl.ts | 4 + translations/ff7tk_re.ts | 4 + 12 files changed, 221 insertions(+), 86 deletions(-) diff --git a/src/data/FF7Save.cpp b/src/data/FF7Save.cpp index 3dd997797..cb55733e7 100644 --- a/src/data/FF7Save.cpp +++ b/src/data/FF7Save.cpp @@ -76,6 +76,29 @@ FF7SaveInfo::FORMAT FF7Save::fileDataFormat(QFile &file) return FF7SaveInfo::FORMAT::UNKNOWN; } } + if ( (file_size == FF7SaveInfo::fileSize(FF7SaveInfo::FORMAT::PS4)) && file.peek(0x00B0 + FF7SaveInfo::fileIdentifier(FF7SaveInfo::FORMAT::PS4).length()).mid(0x00B0,FF7SaveInfo::instance()->fileIdentifier(FF7SaveInfo::FORMAT::PS4).length()) == FF7SaveInfo::instance()->fileIdentifier(FF7SaveInfo::FORMAT::PS4)) { + QTextStream(stdout) + << "[FF7Save::loadFile] PS4 Save " + << file.peek(0x00B0+FF7SaveInfo::instance()->fileIdentifier(FF7SaveInfo::FORMAT::PS4).length()).mid(0x00B0,FF7SaveInfo::instance()->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::instance()->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, 0x10); + QTextStream(stdout) + << "[FF7Save::loadFile] PS4 BIN File Size: " << FF7SaveInfo::instance()->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"; + setFormat(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))) @@ -946,7 +969,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); @@ -963,7 +987,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); @@ -984,7 +1009,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); @@ -1001,7 +1027,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); @@ -1018,7 +1045,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; } @@ -1041,6 +1069,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)); diff --git a/src/data/FF7Save.h b/src/data/FF7Save.h index d77ec9c86..71aa81e43 100644 --- a/src/data/FF7Save.h +++ b/src/data/FF7Save.h @@ -1050,6 +1050,8 @@ class FF7TKDATA_EXPORT FF7Save: public QObject bool fileHasChanged; QString buffer_region; // hold the buffers region data. QString SG_Region_String[15]; + 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); diff --git a/src/data/FF7SaveInfo.cpp b/src/data/FF7SaveInfo.cpp index 79cbe2b39..915022461 100644 --- a/src/data/FF7SaveInfo.cpp +++ b/src/data/FF7SaveInfo.cpp @@ -37,16 +37,18 @@ FF7SaveInfo::~FF7SaveInfo() int FF7SaveInfo::fileSize(FF7SaveInfo::FORMAT format) { switch (format) { - case FORMAT::PSX: return get()->d->PSX_FILE_SIZE; - case FORMAT::PC: return get()->d->PC_FILE_SIZE; - 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::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; - case FORMAT::PGE: return get()->d->PGE_FILE_SIZE; - case FORMAT::PDA: return get()->d->PDA_FILE_SIZE; + case FORMAT::PSX: return instance()->d->PSX_FILE_SIZE; + case FORMAT::PC: return instance()->d->PC_FILE_SIZE; + case FORMAT::VMC: return instance()->d->VMC_FILE_SIZE; + case FORMAT::PSP: return instance()->d->PSP_FILE_SIZE; + case FORMAT::PS3: return instance()->d->PS3_FILE_SIZE; + case FORMAT::PS4: return instance()->d->PS4_FILE_SIZE; + case FORMAT::PS4BIN: return instance()->d->PS4_BINFILE_SIZE; + case FORMAT::DEX: return instance()->d->DEX_FILE_SIZE; + case FORMAT::VGS: return instance()->d->VGS_FILE_SIZE; + case FORMAT::SWITCH: return instance()->d->SWITCH_FILE_SIZE; + case FORMAT::PGE: return instance()->d->PGE_FILE_SIZE; + case FORMAT::PDA: return instance()->d->PDA_FILE_SIZE; default: return 0; } } @@ -54,15 +56,17 @@ int FF7SaveInfo::fileSize(FF7SaveInfo::FORMAT format) int FF7SaveInfo::fileHeaderSize(FF7SaveInfo::FORMAT format) { switch (format) { - case FORMAT::PC: return get()->d->PC_FILE_HEADER_SIZE; - 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::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; - case FORMAT::PGE: return get()->d->PGE_FILE_HEADER_SIZE; - case FORMAT::PDA: return get()->d->PDA_FILE_HEADER_SIZE; + case FORMAT::PC: return instance()->d->PC_FILE_HEADER_SIZE; + case FORMAT::VMC: return instance()->d->VMC_FILE_HEADER_SIZE; + case FORMAT::PSP: return instance()->d->PSP_FILE_HEADER_SIZE; + case FORMAT::PS3: return instance()->d->PS3_FILE_HEADER_SIZE; + case FORMAT::PS4: return instance()->d->PS4_FILE_HEADER_SIZE; + case FORMAT::PS4BIN: return instance()->d->PS4_BINFILE_FILE_ID_SIZE; + case FORMAT::DEX: return instance()->d->DEX_FILE_HEADER_SIZE; + case FORMAT::VGS: return instance()->d->VGS_FILE_HEADER_SIZE; + case FORMAT::SWITCH: return instance()->d->SWITCH_FILE_HEADER_SIZE; + case FORMAT::PGE: return instance()->d->PGE_FILE_HEADER_SIZE; + case FORMAT::PDA: return instance()->d->PDA_FILE_HEADER_SIZE; default: return 0; } } @@ -74,6 +78,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: @@ -89,6 +94,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: @@ -103,7 +109,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: @@ -117,14 +124,16 @@ int FF7SaveInfo::slotCount(FF7SaveInfo::FORMAT format) QByteArray FF7SaveInfo::fileIdentifier(FF7SaveInfo::FORMAT format) { switch (format) { - case FORMAT::PSX: return get()->d->PSX_FILE_ID; - case FORMAT::PC: return get()->d->PC_FILE_ID; - 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::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; + case FORMAT::PSX: return instance()->d->PSX_FILE_ID; + case FORMAT::PC: return instance()->d->PC_FILE_ID; + case FORMAT::VMC: return instance()->d->VMC_FILE_ID; + case FORMAT::PSP: return instance()->d->PSP_FILE_ID; + case FORMAT::PS3: return instance()->d->PS3_FILE_ID; + case FORMAT::PS4: return instance()->d->PS4_FILE_ID; + case FORMAT::PS4BIN: return instance()->d->PS4_BINFILE_FILE_ID; + case FORMAT::DEX: return instance()->d->DEX_FILE_ID; + case FORMAT::VGS: return instance()->d->VGS_FILE_ID; + case FORMAT::SWITCH: return instance()->d->SWITCH_FILE_ID; default: return QByteArray(); } } @@ -137,8 +146,9 @@ QByteArray FF7SaveInfo::fileHeader(FF7SaveInfo::FORMAT format) case FORMAT::DEX: case FORMAT::VGS: 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::PSP: return instance()->d->PSP_FILE_HEADER; + case FORMAT::PS3: return instance()->d->PS3_FILE_HEADER; + case FORMAT::PS4: return instance()->d->PS4_FILE_HEADER; default: return QByteArray(); } } @@ -152,6 +162,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); @@ -167,6 +178,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); @@ -178,7 +190,8 @@ QByteArray FF7SaveInfo::signingKey(FF7SaveInfo::FORMAT format) { switch (format) { case FORMAT::PSP: - case FORMAT::PS3: return get()->d->PS_SIGNING_KEY; + case FORMAT::PS3: return instance()->d->PS_SIGNING_KEY; + case FORMAT::PS4: return instance()->d->PS4_SIGNING_KEY; default: return QByteArray(); } } @@ -198,7 +211,8 @@ QByteArray FF7SaveInfo::signingIV(FF7SaveInfo::FORMAT format) { switch (format) { case FORMAT::PSP: - case FORMAT::PS3: return get()->d->PS_SIGNING_IV; + case FORMAT::PS3: return instance()->d->PS_SIGNING_IV; + case FORMAT::PS4: return instance()->d->PS4_SIGNING_IV; default: return QByteArray(); } } @@ -206,8 +220,9 @@ QByteArray FF7SaveInfo::signingIV(FF7SaveInfo::FORMAT format) 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::PSP: return instance()->d->PSP_SEED_OFFSET; + case FORMAT::PS3: return instance()->d->PS3_SEED_OFFSET; + case FORMAT::PS4: return instance()->d->PS4_SEED_OFFSET; default: return -1; } } @@ -215,8 +230,9 @@ int FF7SaveInfo::fileSeedOffset(FF7SaveInfo::FORMAT format) 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::PSP: return instance()->d->PSP_SIGNATURE_OFFSET; + case FORMAT::PS3: return instance()->d->PS3_SIGNATURE_OFFSET; + case FORMAT::PS4: return instance()->d->PS4_SIGNATURE_OFFSET; default: return -1; } } @@ -225,7 +241,8 @@ int FF7SaveInfo::fileSignatureSize(FF7SaveInfo::FORMAT format) { switch (format) { case FORMAT::PSP: - case FORMAT::PS3: return get()->d->PS_SIGNATURE_SIZE; + case FORMAT::PS3: return instance()->d->PS_SIGNATURE_SIZE; + case FORMAT::PS4: return instance()->d->PS4_SIGNATURE_SIZE; default: return 0; } } @@ -238,16 +255,17 @@ int FF7SaveInfo::slotSize() QRegularExpression FF7SaveInfo::validNames(FF7SaveInfo::FORMAT format) { switch (format) { - case FORMAT::PC: return get()->d->PC_VALID_NAME_REGEX; - 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::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; - case FORMAT::SWITCH: return get()->d->SWITCH_VALID_NAME_REGEX; - case FORMAT::PGE: return get()->d->PGE_VALID_NAME_REGEX; - case FORMAT::PDA: return get()->d->PDA_VALID_NAME_REGEX; + case FORMAT::PC: return instance()->d->PC_VALID_NAME_REGEX; + case FORMAT::PSX: return instance()->d->PSX_VALID_NAME_REGEX; + case FORMAT::PSP: return instance()->d->PSP_VALID_NAME_REGEX; + case FORMAT::PS3: return instance()->d->PS3_VALID_NAME_REGEX; + case FORMAT::PS4: return instance()->d->PS4_VALID_NAME_REGEX; + case FORMAT::DEX: return instance()->d->DEX_VALID_NAME_REGEX; + case FORMAT::VGS: return instance()->d->VGS_VALID_NAME_REGEX; + case FORMAT::VMC: return instance()->d->VMC_VALID_NAME_REGEX; + case FORMAT::SWITCH: return instance()->d->SWITCH_VALID_NAME_REGEX; + case FORMAT::PGE: return instance()->d->PGE_VALID_NAME_REGEX; + case FORMAT::PDA: return instance()->d->PDA_VALID_NAME_REGEX; default: return QRegularExpression(); } } @@ -255,16 +273,17 @@ QRegularExpression FF7SaveInfo::validNames(FF7SaveInfo::FORMAT format) QString FF7SaveInfo::typeDescription(FF7SaveInfo::FORMAT format) { switch (format) { - case FORMAT::PC: return tr(get()->d->PC_FILE_DESCRIPTION.toUtf8()); - 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::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()); - case FORMAT::SWITCH: return tr(get()->d->SWITCH_FILE_DESCRIPTION.toUtf8()); - case FORMAT::PGE: return tr(get()->d->PGE_FILE_DESCRIPTION.toUtf8()); - case FORMAT::PDA: return tr(get()->d->PDA_FILE_DESCRIPTION.toUtf8()); + case FORMAT::PC: return tr(instance()->d->PC_FILE_DESCRIPTION.toUtf8()); + case FORMAT::PSX: return tr(instance()->d->PSX_FILE_DESCRIPTION.toUtf8()); + case FORMAT::PSP: return tr(instance()->d->PSP_FILE_DESCRIPTION.toUtf8()); + case FORMAT::PS3: return tr(instance()->d->PS3_FILE_DESCRIPTION.toUtf8()); + case FORMAT::PS4: return tr(instance()->d->PS4_FILE_DESCRIPTION.toUtf8()); + case FORMAT::DEX: return tr(instance()->d->DEX_FILE_DESCRIPTION.toUtf8()); + case FORMAT::VGS: return tr(instance()->d->VGS_FILE_DESCRIPTION.toUtf8()); + case FORMAT::VMC: return tr(instance()->d->VMC_FILE_DESCRIPTION.toUtf8()); + case FORMAT::SWITCH: return tr(instance()->d->SWITCH_FILE_DESCRIPTION.toUtf8()); + case FORMAT::PGE: return tr(instance()->d->PGE_FILE_DESCRIPTION.toUtf8()); + case FORMAT::PDA: return tr(instance()->d->PDA_FILE_DESCRIPTION.toUtf8()); default: return QString(); } } @@ -272,16 +291,17 @@ QString FF7SaveInfo::typeDescription(FF7SaveInfo::FORMAT format) QStringList FF7SaveInfo::typeExtension(FF7SaveInfo::FORMAT format) { switch (format) { - case FORMAT::PC: return get()->d->PC_VALID_EXTENSIONS; - 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::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; - case FORMAT::SWITCH: return get()->d->SWITCH_VALID_EXTENSIONS; - case FORMAT::PGE: return get()->d->PGE_VALID_EXTENSIONS; - case FORMAT::PDA: return get()->d->PDA_VALID_EXTENSIONS; + case FORMAT::PC: return instance()->d->PC_VALID_EXTENSIONS; + case FORMAT::PSX: return instance()->d->PSX_VALID_EXTENSIONS; + case FORMAT::PSP: return instance()->d->PSP_VALID_EXTENSIONS; + case FORMAT::PS3: return instance()->d->PS3_VALID_EXTENSIONS; + case FORMAT::PS4: return instance()->d->PS4_VALID_EXTENSIONS; + case FORMAT::DEX: return instance()->d->DEX_VALID_EXTENSIONS; + case FORMAT::VGS: return instance()->d->VGS_VALID_EXTENSIONS; + case FORMAT::VMC: return instance()->d->VMC_VALID_EXTENSIONS; + case FORMAT::SWITCH: return instance()->d->SWITCH_VALID_EXTENSIONS; + case FORMAT::PGE: return instance()->d->PGE_VALID_EXTENSIONS; + case FORMAT::PDA: return instance()->d->PDA_VALID_EXTENSIONS; default: return QStringList(); } } @@ -296,25 +316,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") - .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->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") + QString allTypes = QStringLiteral("%1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11") + .arg(instance()->d->PC_VALID_EXTENSIONS.join(space) + , instance()->d->PSX_VALID_EXTENSIONS.join(space) + , instance()->d->PSP_VALID_EXTENSIONS.join(space) + , instance()->d->PS3_VALID_EXTENSIONS.join(space) + , instance()->d->PS4_VALID_EXTENSIONS.join(space) + , instance()->d->DEX_VALID_EXTENSIONS.join(space) + , instance()->d->VGS_VALID_EXTENSIONS.join(space) + , instance()->d->VMC_VALID_EXTENSIONS.join(space) + , instance()->d->SWITCH_VALID_EXTENSIONS.join(space) + , instance()->d->PGE_VALID_EXTENSIONS.join(space) + , instance()->d->PDA_VALID_EXTENSIONS.join(space)); + + 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) @@ -327,6 +349,7 @@ bool FF7SaveInfo::isTypePC(FF7SaveInfo::FORMAT format) { switch(format) { case FORMAT::SWITCH: + case FORMAT::PS4: case FORMAT::PC: return true; default: return false; }; @@ -380,4 +403,3 @@ QByteArray FF7SaveInfo::defaultSaveData() { return get()->d->DEFAULT_SAVE; } - diff --git a/src/data/FF7SaveInfo.h b/src/data/FF7SaveInfo.h index 75fca05c5..25946f839 100644 --- a/src/data/FF7SaveInfo.h +++ b/src/data/FF7SaveInfo.h @@ -15,6 +15,17 @@ /****************************************************************************/ #pragma once +#ifdef _MSC_VER +# define PACK(structure) \ + __pragma(pack(push, 1)) \ + structure \ + __pragma(pack(pop)) +#elif defined(__MINGW32__) +#define PACK(structure) structure __attribute__ ((gcc_struct, __packed__)) +#else +#define PACK(structure) structure Q_PACKED +#endif + #include #include #if QT_VERSION < QT_VERSION_CHECK(6, 5, 0) @@ -48,6 +59,8 @@ class FF7TKDATA_EXPORT FF7SaveInfo : public QObject SWITCH = 7, //!< Switch Format PGE = 8, //!< Psx Game Edit Style Single Save PDA = 9, //!< GS , Dantel Style Save + PS4 = 10, //!< PS4 Save Format + PS4BIN = 11 //!< PS4 BIN File (pfsSKKey) }; Q_ENUM(FORMAT) @@ -75,6 +88,21 @@ class FF7TKDATA_EXPORT FF7SaveInfo : public QObject }; Q_ENUM(PSVINFO) + /** + * \struct pfsSKKey + * \brief Extra bin file (Sealedkey) used for PS4 format + */ +PACK( + struct pfsSKKey { + quint8 MAGIC[8]; /**< [0x0000] MAGIC (0x08) */ + quint16 KEYSET; /**< [0x0008] KEYSET (0x02) */ + quint8 pad[6]; /**< [0x000A] Padding zeros (0x06) */ + quint8 IV[16]; /**< [0x0010] AES IV (0x10) */ + quint8 KEY[32]; /**< [0x0020] AES KEY (0x20) */ + quint8 SHA256[32]; /**< [0x0040] AES SHA256 (0x20) */ + } +); + /** * @brief Get the FF7SaveInfo Instance. */ @@ -343,6 +371,28 @@ class FF7TKDATA_EXPORT FF7SaveInfo : public QObject inline static const int PS_SIGNATURE_SIZE = 0x0014; inline static const QByteArray PS_SIGNING_KEY= QByteArray::fromRawData("\xAB\x5A\xBC\x9F\xC1\xF4\x9D\xE6\xA0\x51\xDB\xAE\xFA\x51\x88\x59", 0x10); inline static const QByteArray PS_SIGNING_IV= QByteArray::fromRawData("\xB3\x0F\xFE\xED\xB7\xDC\x5E\xB7\x13\x3D\xA6\x0D\x1B\x6B\x2C\xDC", 0x10); + /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~PS4 SAVE INFO~~~~~~~~~~~~~~~~~~~~~~~~~*/ + static const int PS4_FILE_SIZE = 0xA00000; + static const int PS4_FILE_HEADER_SIZE = 0x00AF; + inline static const QString PS4_FILE_DESCRIPTION = QT_TR_NOOP("PS4 Save File"); + inline static const QStringList PS4_VALID_EXTENSIONS { QStringLiteral("*.ff7") }; + inline static const QRegularExpression PS4_VALID_NAME_REGEX = QRegularExpression(QStringLiteral("save0[0-9].ff7")); + inline static const QByteArray PS4_FILE_ID = QByteArray::fromRawData("\x17\x00\x00\x00\x00\x00\x00\x00", 8); + inline static const QByteArray PS4_BINFILE_FILE_ID = QByteArray::fromRawData("\x70\x66\x73\x53\x4B\x4B\x65\x79", 8); + static const int PS4_BINFILE_FILE_ID_SIZE = 8; + static const int PS4_BINFILE_SIZE = 0x60; + static const int PS4_BINFILE_IV_OFFSET= 0x10; + static const int PS4_BINFILE_IV_SIZE= 0x10; + static const int PS4_SEED_OFFSET = 0x0008; + static const int PS4_SIGNATURE_OFFSET = 0x001C; + static const int PS4_FILE_TYPE_OFFSET = 0x0038; + static const int PS4_FILE_DISP_SIZE_OFFSET = 0x0040; + static const int PS4_FILE_SIZE_OFFSET = 0x005C; + inline static const QByteArray PS4_FILE_HEADER = QByteArray::fromRawData("\x00\x56\x53\x50\x00\x00\x00\x00\x04\xbc\x97\x58\x11\x0f\x7e\x85\xc7\x4f\x2f\xd0\x5a\x28\xb6\x25\xe6\x9a\x6e\xa1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14\x00\x00\x00\x01\x00\x00\x00\x00\x20\x00\x00\x84\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x03\x90\x00\x00\x42\x41\x53\x43\x55\x53\x2d\x39\x34\x31\x36\x33\x46\x46\x37\x2d\x53\x30\x31\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", PS3_FILE_HEADER_SIZE); + /*~~~~~~~ PS4 Signing ~~~~~~~~~~~~~~*/ + static const int PS4_SIGNATURE_SIZE = 0x0014; + inline static const QByteArray PS4_SIGNING_KEY= QByteArray::fromRawData("\xAB\x5A\xBC\x9F\xC1\xF4\x9D\xE6\xA0\x51\xDB\xAE\xFA\x51\x88\x59", 0x10); + inline static const QByteArray PS4_SIGNING_IV= QByteArray::fromRawData("\xB3\x0F\xFE\xED\xB7\xDC\x5E\xB7\x13\x3D\xA6\x0D\x1B\x6B\x2C\xDC", 0x10); /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Mem Card Format~~~~~~~~~~~~~~~~~~~*/ inline static const int VMC_FILE_SIZE = 0x20000; inline static const int VMC_FILE_HEADER_SIZE = 0x2000; diff --git a/translations/ff7tk_de.ts b/translations/ff7tk_de.ts index 54c4f5d96..a27971a57 100644 --- a/translations/ff7tk_de.ts +++ b/translations/ff7tk_de.ts @@ -6915,6 +6915,10 @@ Die km / h beschleunigt berechnet werden während des Spielens XP AR GS Caetla SmartLink Dantel XP AR GS Caetla SmartLink Dantel + + PS4 Save File + PS4 Spielstand + ItemList diff --git a/translations/ff7tk_en.ts b/translations/ff7tk_en.ts index a03b0703b..f2e845b59 100644 --- a/translations/ff7tk_en.ts +++ b/translations/ff7tk_en.ts @@ -6915,6 +6915,10 @@ The km/h speeds are calculated while playing XP AR GS Caetla SmartLink Dantel XP AR GS Caetla SmartLink Dantel + + PS4 Save File + PS4 Save File + ItemList diff --git a/translations/ff7tk_es.ts b/translations/ff7tk_es.ts index 5fae9345d..0f38c5671 100644 --- a/translations/ff7tk_es.ts +++ b/translations/ff7tk_es.ts @@ -6915,6 +6915,10 @@ Los km/h son calculados mientras se juega XP AR GS Caetla SmartLink Dantel XP AR GS Caetla SmartLink Dantel + + PS4 Save File + Partida Guardada PS4 + ItemList diff --git a/translations/ff7tk_fr.ts b/translations/ff7tk_fr.ts index 03f03e6ec..71adf8414 100644 --- a/translations/ff7tk_fr.ts +++ b/translations/ff7tk_fr.ts @@ -6915,6 +6915,10 @@ Les vitesses en km/h sont calculés pendant le jeu XP AR GS Caetla SmartLink Dantel XP AR GS Caetla SmartLink Dantel + + PS4 Save File + Sauvegarde PS4 + ItemList diff --git a/translations/ff7tk_it.ts b/translations/ff7tk_it.ts index b17e07ec3..493f270fa 100644 --- a/translations/ff7tk_it.ts +++ b/translations/ff7tk_it.ts @@ -6926,6 +6926,10 @@ Battaglia %1 Known FF7 Save Types (%1) File di salvataggio FF7 noti (%1) + + PS4 Save File + File di salvataggio PS4 + ItemList diff --git a/translations/ff7tk_ja.ts b/translations/ff7tk_ja.ts index 86c3cf123..4fc512b46 100644 --- a/translations/ff7tk_ja.ts +++ b/translations/ff7tk_ja.ts @@ -6915,6 +6915,10 @@ The km/h speeds are calculated while playing XP AR GS Caetla SmartLink Dantel XP AR GS Caetla SmartLink Dantel + + PS4 Save File + PS4 セーブ + ItemList diff --git a/translations/ff7tk_pl.ts b/translations/ff7tk_pl.ts index f1e589263..bfa7e7c5f 100644 --- a/translations/ff7tk_pl.ts +++ b/translations/ff7tk_pl.ts @@ -6914,6 +6914,10 @@ The km/h speeds are calculated while playing Known FF7 Save Types (%1) Znane Typy Plików FF7 (%1) + + PS4 Save File + Zapisz Plik PS4 + ItemList diff --git a/translations/ff7tk_re.ts b/translations/ff7tk_re.ts index b98f74d0d..e0e0c1dba 100644 --- a/translations/ff7tk_re.ts +++ b/translations/ff7tk_re.ts @@ -6915,6 +6915,10 @@ The km/h speeds are calculated while playing Known FF7 Save Types (%1) Known FF7 Save Types (%1) + + PS4 Save File + PS4 Save File + ItemList