Path: blob/master/RSDKv5/RSDK/Core/Reader.cpp
1163 views
#include "RSDK/Core/RetroEngine.hpp"12using namespace RSDK;34RSDKFileInfo RSDK::dataFileList[DATAFILE_COUNT];5RSDKContainer RSDK::dataPacks[DATAPACK_COUNT];67uint8 RSDK::dataPackCount = 0;8uint16 RSDK::dataFileListCount = 0;910char RSDK::gameLogicName[0x200];1112bool32 RSDK::useDataPack = false;1314#if RETRO_REV0U15void RSDK::DetectEngineVersion()16{17bool32 readDataPack = useDataPack;18#if RETRO_USE_MOD_LOADER19// mods can manually set their target engine versions if needed20if (modSettings.versionOverride) {21engine.version = modSettings.versionOverride;22return;23}2425// check if we have any mods with gameconfigs26int32 m = 0;27for (m = 0; m < modList.size(); ++m) {28if (!modList[m].active)29break;30SetActiveMod(m);3132FileInfo checkInfo;33InitFileInfo(&checkInfo);34if (LoadFile(&checkInfo, "Data/Game/GameConfig.bin", FMODE_RB)) {35readDataPack = false;36CloseFile(&checkInfo);37m = 0; // found one, just sets this to 0 again38break;39}40}4142if (m) // didn't find a gameconfig43SetActiveMod(-1);44#endif4546FileInfo info;47InitFileInfo(&info);48if (!readDataPack) {49if (LoadFile(&info, "Data/Game/GameConfig.bin", FMODE_RB)) {50#if RETRO_USE_MOD_LOADER51SetActiveMod(-1);52#endif53uint32 sig = ReadInt32(&info, false);5455// GameConfig has "CFG" signature, its RSDKv5 formatted56if (sig == RSDK_SIGNATURE_CFG) {57engine.version = 5;58}59else {60// else, assume its RSDKv4 for now61engine.version = 4;6263// Go back to the start of the file to check v3's "Data" string, that way we can tell if its v3 or v464Seek_Set(&info, 0);6566uint8 length = ReadInt8(&info);67char buffer[0x40];68ReadBytes(&info, buffer, length);6970// the "Data" thing is actually a string, but lets treat it as a "signature" for simplicity's sake shall we?71length = ReadInt8(&info);72uint32 sig = ReadInt32(&info, false);73if (sig == RSDK_SIGNATURE_DATA && length == 4)74engine.version = 3;75}7677CloseFile(&info);78}79}80else {81info.externalFile = true;82if (LoadFile(&info, dataPacks[dataPackCount - 1].name, FMODE_RB)) {83uint32 sig = ReadInt32(&info, false);84if (sig == RSDK_SIGNATURE_RSDK) {85ReadInt8(&info); // 'v'86uint8 version = ReadInt8(&info);8788switch (version) {89default: break;90case '3': engine.version = 3; break;91case '4': engine.version = 4; break;92case '5': engine.version = 5; break;93}94}95else {96// v3 has no 'RSDK' signature97engine.version = 3;98}99100CloseFile(&info);101}102}103}104#endif105106bool32 RSDK::LoadDataPack(const char *filePath, size_t fileOffset, bool32 useBuffer)107{108MEM_ZERO(dataPacks[dataPackCount]);109useDataPack = false;110FileInfo info;111112char dataPackPath[0x100];113sprintf_s(dataPackPath, sizeof(dataPackPath), "%s%s", SKU::userFileDir, filePath);114115InitFileInfo(&info);116info.externalFile = true;117if (LoadFile(&info, dataPackPath, FMODE_RB)) {118uint32 sig = ReadInt32(&info, false);119if (sig != RSDK_SIGNATURE_RSDK)120return false;121122useDataPack = true;123124ReadInt8(&info); // 'v'125ReadInt8(&info); // version126127strcpy(dataPacks[dataPackCount].name, dataPackPath);128129dataPacks[dataPackCount].fileCount = ReadInt16(&info);130for (int32 f = 0; f < dataPacks[dataPackCount].fileCount; ++f) {131uint8 b[4];132for (int32 y = 0; y < 4; y++) {133ReadBytes(&info, b, 4);134dataFileList[f].hash[y] = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3] << 0);135}136137dataFileList[f].offset = ReadInt32(&info, false);138dataFileList[f].size = ReadInt32(&info, false);139140dataFileList[f].encrypted = (dataFileList[f].size & 0x80000000) != 0;141dataFileList[f].size &= 0x7FFFFFFF;142dataFileList[f].useFileBuffer = useBuffer;143dataFileList[f].packID = dataPackCount;144}145146dataPacks[dataPackCount].fileBuffer = NULL;147if (useBuffer) {148dataPacks[dataPackCount].fileBuffer = (uint8 *)malloc(info.fileSize);149Seek_Set(&info, 0);150ReadBytes(&info, dataPacks[dataPackCount].fileBuffer, info.fileSize);151}152153dataFileListCount += dataPacks[dataPackCount].fileCount;154dataPackCount++;155156CloseFile(&info);157158return true;159}160else {161useDataPack = false;162return false;163}164}165166#if !RETRO_USE_ORIGINAL_CODE && RETRO_REV0U167inline bool ends_with(std::string const &value, std::string const &ending)168{169if (ending.size() > value.size())170return false;171return std::equal(ending.rbegin(), ending.rend(), value.rbegin());172}173#endif174175bool32 RSDK::OpenDataFile(FileInfo *info, const char *filename)176{177char hashBuffer[0x400];178StringLowerCase(hashBuffer, filename);179RETRO_HASH_MD5(hash);180GEN_HASH_MD5_BUFFER(hashBuffer, hash);181182for (int32 f = 0; f < dataFileListCount; ++f) {183RSDKFileInfo *file = &dataFileList[f];184185if (!HASH_MATCH_MD5(hash, file->hash))186continue;187188info->usingFileBuffer = file->useFileBuffer;189if (!file->useFileBuffer) {190info->file = fOpen(dataPacks[file->packID].name, "rb");191if (!info->file) {192PrintLog(PRINT_NORMAL, "File not found (Unable to open datapack): %s", filename);193return false;194}195196fSeek(info->file, file->offset, SEEK_SET);197}198else {199// a bit of a hack, but it is how it is in the original200info->file = (FileIO *)&dataPacks[file->packID].fileBuffer[file->offset];201202uint8 *fileBuffer = (uint8 *)info->file;203info->fileBuffer = fileBuffer;204}205206info->fileSize = file->size;207info->readPos = 0;208info->fileOffset = file->offset;209info->encrypted = file->encrypted;210memset(info->encryptionKeyA, 0, 0x10 * sizeof(uint8));211memset(info->encryptionKeyB, 0, 0x10 * sizeof(uint8));212if (info->encrypted) {213GenerateELoadKeys(info, filename, info->fileSize);214info->eKeyNo = (info->fileSize / 4) & 0x7F;215info->eKeyPosA = 0;216info->eKeyPosB = 8;217info->eNybbleSwap = false;218}219220#if !RETRO_USE_ORIGINAL_CODE221PrintLog(PRINT_NORMAL, "Loaded data file %s", filename);222#endif223return true;224}225226#if !RETRO_USE_ORIGINAL_CODE227PrintLog(PRINT_NORMAL, "Data file not found: %s", filename);228#else229PrintLog(PRINT_NORMAL, "File not found: %s", filename);230#endif231return false;232}233234bool32 RSDK::LoadFile(FileInfo *info, const char *filename, uint8 fileMode)235{236if (info->file)237return false;238239char fullFilePath[0x100];240strcpy(fullFilePath, filename);241242#if RETRO_USE_MOD_LOADER243char pathLower[0x100];244memset(pathLower, 0, sizeof(pathLower));245for (int32 c = 0; c < strlen(filename); ++c) pathLower[c] = tolower(filename[c]);246247bool32 addPath = false;248int32 m = modSettings.activeMod != -1 ? modSettings.activeMod : 0;249for (; m < modList.size(); ++m) {250if (modList[m].active) {251std::map<std::string, std::string>::const_iterator iter = modList[m].fileMap.find(pathLower);252if (iter != modList[m].fileMap.cend()) {253if (std::find(modList[m].excludedFiles.begin(), modList[m].excludedFiles.end(), pathLower) == modList[m].excludedFiles.end()) {254strcpy(fullFilePath, iter->second.c_str());255info->externalFile = true;256break;257}258else {259PrintLog(PRINT_NORMAL, "[MOD] Excluded File: %s", filename);260}261}262}263if (modSettings.activeMod != -1) {264PrintLog(PRINT_NORMAL, "[MOD] Failed to find file %s in active mod %s", filename, modList[m].id.c_str());265// TODO return false? check original impl later266}267}268269#if RETRO_REV0U270if (modSettings.forceScripts && !info->externalFile) {271if (std::string(fullFilePath).rfind("Data/Scripts/", 0) == 0 && ends_with(std::string(fullFilePath), "txt")) {272// is a script, since those dont exist normally, load them from "scripts/"273info->externalFile = true;274addPath = true;275std::string fStr = std::string(fullFilePath);276fStr.erase(fStr.begin(), fStr.begin() + 5); // remove "Data/"277StrCopy(fullFilePath, fStr.c_str());278}279}280#endif281282#if RETRO_PLATFORM == RETRO_OSX || RETRO_PLATFORM == RETRO_ANDROID283if (addPath) {284char pathBuf[0x100];285sprintf_s(pathBuf, sizeof(pathBuf), "%s%s", SKU::userFileDir, fullFilePath);286sprintf_s(fullFilePath, sizeof(fullFilePath), "%s", pathBuf);287}288#else289(void)addPath;290#endif // ! RETRO_PLATFORM291#endif // ! RETRO_MOD_LOADER292293#if !RETRO_USE_ORIGNAL_CODE294// somewhat hacky that also pleases the mod gods295if (!info->externalFile) {296char pathBuf[0x100];297sprintf_s(pathBuf, sizeof(pathBuf), "%s%s", SKU::userFileDir, fullFilePath);298sprintf_s(fullFilePath, sizeof(fullFilePath), "%s", pathBuf);299}300#endif301302if (!info->externalFile && fileMode == FMODE_RB && useDataPack) {303return OpenDataFile(info, filename);304}305306if (fileMode == FMODE_RB || fileMode == FMODE_WB || fileMode == FMODE_RB_PLUS) {307info->file = fOpen(fullFilePath, openModes[fileMode - 1]);308}309310if (!info->file) {311#if !RETRO_USE_ORIGINAL_CODE312PrintLog(PRINT_NORMAL, "File not found: %s", fullFilePath);313#endif314return false;315}316317info->readPos = 0;318info->fileSize = 0;319320if (fileMode != FMODE_WB) {321fSeek(info->file, 0, SEEK_END);322info->fileSize = (int32)fTell(info->file);323fSeek(info->file, 0, SEEK_SET);324}325#if !RETRO_USE_ORIGINAL_CODE326PrintLog(PRINT_NORMAL, "Loaded file %s", fullFilePath);327#endif328return true;329}330331void RSDK::GenerateELoadKeys(FileInfo *info, const char *key1, int32 key2)332{333// This function splits hashes into bytes by casting their integers to byte arrays,334// which only works as intended on little-endian CPUs.335#if !RETRO_USE_ORIGINAL_CODE336RETRO_HASH_MD5(hash);337#else338uint8 hash[0x10];339#endif340char hashBuffer[0x400];341342// KeyA343StringUpperCase(hashBuffer, key1);344#if !RETRO_USE_ORIGINAL_CODE345GEN_HASH_MD5_BUFFER(hashBuffer, hash);346347for (int32 i = 0; i < 4; ++i)348for (int32 j = 0; j < 4; ++j) info->encryptionKeyA[i * 4 + j] = (hash[i] >> (8 * (j ^ 3))) & 0xFF;349#else350GEN_HASH_MD5_BUFFER(hashBuffer, (uint32 *)hash);351352for (int32 y = 0; y < 0x10; y += 4) {353info->encryptionKeyA[y + 3] = hash[y + 0];354info->encryptionKeyA[y + 2] = hash[y + 1];355info->encryptionKeyA[y + 1] = hash[y + 2];356info->encryptionKeyA[y + 0] = hash[y + 3];357}358#endif359360// KeyB361sprintf_s(hashBuffer, sizeof(hashBuffer), "%d", key2);362#if !RETRO_USE_ORIGINAL_CODE363GEN_HASH_MD5_BUFFER(hashBuffer, hash);364365for (int32 i = 0; i < 4; ++i)366for (int32 j = 0; j < 4; ++j) info->encryptionKeyB[i * 4 + j] = (hash[i] >> (8 * (j ^ 3))) & 0xFF;367#else368GEN_HASH_MD5_BUFFER(hashBuffer, (uint32 *)hash);369370for (int32 y = 0; y < 0x10; y += 4) {371info->encryptionKeyB[y + 3] = hash[y + 0];372info->encryptionKeyB[y + 2] = hash[y + 1];373info->encryptionKeyB[y + 1] = hash[y + 2];374info->encryptionKeyB[y + 0] = hash[y + 3];375}376#endif377}378379void RSDK::DecryptBytes(FileInfo *info, void *buffer, size_t size)380{381if (size) {382uint8 *data = (uint8 *)buffer;383while (size > 0) {384*data ^= info->eKeyNo ^ info->encryptionKeyB[info->eKeyPosB];385if (info->eNybbleSwap)386*data = ((*data << 4) + (*data >> 4)) & 0xFF;387*data ^= info->encryptionKeyA[info->eKeyPosA];388389info->eKeyPosA++;390info->eKeyPosB++;391392if (info->eKeyPosA <= 15) {393if (info->eKeyPosB > 12) {394info->eKeyPosB = 0;395info->eNybbleSwap ^= 1;396}397}398else if (info->eKeyPosB <= 8) {399info->eKeyPosA = 0;400info->eNybbleSwap ^= 1;401}402else {403info->eKeyNo += 2;404info->eKeyNo &= 0x7F;405406if (info->eNybbleSwap) {407info->eNybbleSwap = false;408409info->eKeyPosA = info->eKeyNo % 7;410info->eKeyPosB = (info->eKeyNo % 12) + 2;411}412else {413info->eNybbleSwap = true;414415info->eKeyPosA = (info->eKeyNo % 12) + 3;416info->eKeyPosB = info->eKeyNo % 7;417}418}419420++data;421--size;422}423}424}425void RSDK::SkipBytes(FileInfo *info, int32 size)426{427if (size) {428while (size > 0) {429info->eKeyPosA++;430info->eKeyPosB++;431432if (info->eKeyPosA <= 15) {433if (info->eKeyPosB > 12) {434info->eKeyPosB = 0;435info->eNybbleSwap ^= 1;436}437}438else if (info->eKeyPosB <= 8) {439info->eKeyPosA = 0;440info->eNybbleSwap ^= 1;441}442else {443info->eKeyNo += 2;444info->eKeyNo &= 0x7F;445446if (info->eNybbleSwap) {447info->eNybbleSwap = false;448449info->eKeyPosA = info->eKeyNo % 7;450info->eKeyPosB = (info->eKeyNo % 12) + 2;451}452else {453info->eNybbleSwap = true;454455info->eKeyPosA = (info->eKeyNo % 12) + 3;456info->eKeyPosB = info->eKeyNo % 7;457}458}459460--size;461}462}463}464465466