diff --git a/src/data/FF7Save.cpp b/src/data/FF7Save.cpp index 3f615d145..bb629f43d 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))) @@ -944,7 +967,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); @@ -961,7 +985,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); @@ -982,7 +1007,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); @@ -999,7 +1025,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); @@ -1016,7 +1043,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; } @@ -1039,6 +1067,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 d123daed5..2632d27d9 100644 --- a/src/data/FF7Save.h +++ b/src/data/FF7Save.h @@ -1043,6 +1043,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 f1c0d6f32..66ae40565 100644 --- a/src/data/FF7SaveInfo.cpp +++ b/src/data/FF7SaveInfo.cpp @@ -18,7 +18,6 @@ #include #include - FF7SaveInfo *FF7SaveInfo::instance() { static FF7SaveInfo m; @@ -51,6 +50,8 @@ int FF7SaveInfo::fileSize(FF7SaveInfo::FORMAT format) 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; @@ -67,6 +68,8 @@ int FF7SaveInfo::fileHeaderSize(FF7SaveInfo::FORMAT format) 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; @@ -83,6 +86,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: @@ -98,6 +102,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: @@ -112,7 +117,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: @@ -131,6 +137,8 @@ QByteArray FF7SaveInfo::fileIdentifier(FF7SaveInfo::FORMAT format) 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; @@ -148,6 +156,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 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(); } } @@ -161,6 +170,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(instance()->d->PSX_SLOT_HEADER.at(slot)).append(256, 0x00); @@ -176,6 +186,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(instance()->d->PSX_SLOT_FOOTER_SIZE, 0x00); @@ -188,6 +199,7 @@ QByteArray FF7SaveInfo::signingKey(FF7SaveInfo::FORMAT format) switch (format) { case FORMAT::PSP: case FORMAT::PS3: return instance()->d->PS_SIGNING_KEY; + case FORMAT::PS4: return instance()->d->PS4_SIGNING_KEY; default: return QByteArray(); } } @@ -208,6 +220,7 @@ QByteArray FF7SaveInfo::signingIV(FF7SaveInfo::FORMAT format) switch (format) { case FORMAT::PSP: case FORMAT::PS3: return instance()->d->PS_SIGNING_IV; + case FORMAT::PS4: return instance()->d->PS4_SIGNING_IV; default: return QByteArray(); } } @@ -217,6 +230,7 @@ int FF7SaveInfo::fileSeedOffset(FF7SaveInfo::FORMAT format) switch (format) { 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; } } @@ -226,6 +240,7 @@ int FF7SaveInfo::fileSignatureOffset(FF7SaveInfo::FORMAT format) switch (format) { 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; } } @@ -235,6 +250,7 @@ int FF7SaveInfo::fileSignatureSize(FF7SaveInfo::FORMAT format) switch (format) { case FORMAT::PSP: case FORMAT::PS3: return instance()->d->PS_SIGNATURE_SIZE; + case FORMAT::PS4: return instance()->d->PS4_SIGNATURE_SIZE; default: return 0; } } @@ -251,6 +267,7 @@ QRegularExpression FF7SaveInfo::validNames(FF7SaveInfo::FORMAT format) 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; @@ -268,6 +285,7 @@ QString FF7SaveInfo::typeDescription(FF7SaveInfo::FORMAT format) 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()); @@ -285,6 +303,7 @@ QStringList FF7SaveInfo::typeExtension(FF7SaveInfo::FORMAT format) 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; @@ -305,11 +324,12 @@ 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(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) @@ -317,13 +337,14 @@ QString FF7SaveInfo::knownTypesFilter() , 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") + 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) @@ -336,6 +357,7 @@ bool FF7SaveInfo::isTypePC(FF7SaveInfo::FORMAT format) { switch(format) { case FORMAT::SWITCH: + case FORMAT::PS4: case FORMAT::PC: return true; default: return false; }; @@ -384,4 +406,3 @@ int FF7SaveInfo::psxSaveNameOffset(FF7SaveInfo::FORMAT format) default: return -1; } } - diff --git a/src/data/FF7SaveInfo.h b/src/data/FF7SaveInfo.h index ef23620db..75a1b9e38 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 #include @@ -42,6 +53,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) @@ -69,6 +82,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. * @sa qmlSingletonRegister() @@ -330,6 +358,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 0b50c7cd5..613bdb996 100644 --- a/translations/ff7tk_de.ts +++ b/translations/ff7tk_de.ts @@ -6872,6 +6872,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 1a680e316..55262f9d8 100644 --- a/translations/ff7tk_en.ts +++ b/translations/ff7tk_en.ts @@ -6872,6 +6872,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 9ace07f5a..dfcccc004 100644 --- a/translations/ff7tk_es.ts +++ b/translations/ff7tk_es.ts @@ -6872,6 +6872,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 8536bd788..9326a9783 100644 --- a/translations/ff7tk_fr.ts +++ b/translations/ff7tk_fr.ts @@ -6872,6 +6872,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 b58997ee9..8b12ef554 100644 --- a/translations/ff7tk_it.ts +++ b/translations/ff7tk_it.ts @@ -6881,6 +6881,10 @@ La velocità in km/h viene calcolata a runtime 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 6da40a4a4..f49564e13 100644 --- a/translations/ff7tk_ja.ts +++ b/translations/ff7tk_ja.ts @@ -6872,6 +6872,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 4cc04e40e..089679730 100644 --- a/translations/ff7tk_pl.ts +++ b/translations/ff7tk_pl.ts @@ -6871,6 +6871,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 355b5406f..97816818b 100644 --- a/translations/ff7tk_re.ts +++ b/translations/ff7tk_re.ts @@ -6872,6 +6872,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