Path: blob/main/RSDKv4/Reader.cpp
817 views
#include "RetroEngine.hpp"1#include <string>23RSDKContainer rsdkContainer;45char fileName[0x100];6byte fileBuffer[0x2000];7int fileSize = 0;8int vFileSize = 0;9int readPos = 0;10int readSize = 0;11int bufferPosition = 0;12int virtualFileOffset = 0;13bool useEncryption = false;14byte packID = 0;15byte eStringPosA;16byte eStringPosB;17byte eStringNo;18byte eNybbleSwap;19byte encryptionStringA[0x10];20byte encryptionStringB[0x10];2122FileIO *cFileHandle = nullptr;2324bool CheckRSDKFile(const char *filePath)25{26FileInfo info;2728char filePathBuffer[0x100];29#if RETRO_PLATFORM == RETRO_OSX30char pathBuf[0x100];31sprintf(pathBuf, "%s/%s", gamePath, filePath);32sprintf(filePathBuffer, "%s", pathBuf);33#else34sprintf(filePathBuffer, "%s", filePath);35#endif3637cFileHandle = fOpen(filePathBuffer, "rb");38if (cFileHandle) {39byte signature[6] = { 'R', 'S', 'D', 'K', 'v', 'B' };40byte buf = 0;41for (int i = 0; i < 6; ++i) {42fRead(&buf, 1, 1, cFileHandle);43if (buf != signature[i])44return false;45}4647Engine.usingDataFile = true;48#if !RETRO_USE_ORIGINAL_CODE49Engine.usingDataFile_Config = true;50#endif5152StrCopy(rsdkContainer.packNames[rsdkContainer.packCount], filePathBuffer);5354byte b[4];55fRead(&b, 2, 1, cFileHandle);56ushort fileCount = (b[1] << 8) | (b[0] << 0);57for (int f = 0; f < fileCount; ++f) {58for (int y = 0; y < 4; ++y) {59fRead(b, 1, 4, cFileHandle);60rsdkContainer.files[f].hash[y] = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3] << 0);61}6263fRead(b, 4, 1, cFileHandle);64rsdkContainer.files[f].offset = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | (b[0] << 0);65fRead(b, 4, 1, cFileHandle);66rsdkContainer.files[f].filesize = (b[3] << 24) | (b[2] << 16) | (b[1] << 8) | (b[0] << 0);6768rsdkContainer.files[f].encrypted = (rsdkContainer.files[f].filesize & 0x80000000);69rsdkContainer.files[f].filesize &= 0x7FFFFFFF;7071rsdkContainer.files[f].packID = rsdkContainer.packCount;7273rsdkContainer.fileCount++;74}7576fClose(cFileHandle);77cFileHandle = NULL;78if (LoadFile("Bytecode/GlobalCode.bin", &info)) {79Engine.usingBytecode = true;80CloseFile();81}82PrintLog("loaded datapack '%s'", filePathBuffer);8384rsdkContainer.packCount++;85return true;86}87else {88Engine.usingDataFile = false;89#if !RETRO_USE_ORIGINAL_CODE90Engine.usingDataFile_Config = false;91#endif92cFileHandle = NULL;9394if (LoadFile("Bytecode/GlobalCode.bin", &info)) {95Engine.usingBytecode = true;96CloseFile();97}98PrintLog("Couldn't load datapack '%s'", filePathBuffer);99return false;100}101}102103#if !RETRO_USE_ORIGINAL_CODE104int CheckFileInfo(const char *filepath)105{106char pathBuf[0x100];107StrCopy(pathBuf, filepath);108uint hash[4];109int len = StrLength(pathBuf);110GenerateMD5FromString(pathBuf, len, &hash[0], &hash[1], &hash[2], &hash[3]);111112for (int f = 0; f < rsdkContainer.fileCount; ++f) {113RSDKFileInfo *file = &rsdkContainer.files[f];114115bool match = true;116for (int h = 0; h < 4; ++h) {117if (hash[h] != file->hash[h]) {118match = false;119break;120}121}122if (!match)123continue;124125return f;126}127return -1;128}129130inline bool ends_with(std::string const &value, std::string const &ending)131{132if (ending.size() > value.size())133return false;134return std::equal(ending.rbegin(), ending.rend(), value.rbegin());135}136#endif137138bool LoadFile(const char *filePath, FileInfo *fileInfo)139{140MEM_ZEROP(fileInfo);141142if (cFileHandle)143fClose(cFileHandle);144145char filePathBuf[0x100];146StrCopy(filePathBuf, filePath);147bool forceFolder = false;148#if RETRO_USE_MOD_LOADER149// Fixes ".ani" ".Ani" bug and any other case differences150char pathLower[0x100];151memset(pathLower, 0, sizeof(char) * 0x100);152for (int c = 0; c < strlen(filePathBuf); ++c) {153pathLower[c] = tolower(filePathBuf[c]);154}155156bool addPath = true;157int m = activeMod != -1 ? activeMod : 0;158for (; m < modList.size(); ++m) {159if (modList[m].active) {160std::map<std::string, std::string>::const_iterator iter = modList[m].fileMap.find(pathLower);161if (iter != modList[m].fileMap.cend()) {162StrCopy(filePathBuf, iter->second.c_str());163forceFolder = true;164addPath = false;165break;166}167}168if (activeMod != -1)169break;170}171172if (forceUseScripts && !forceFolder) {173if (std::string(filePathBuf).rfind("Data/Scripts/", 0) == 0 && ends_with(std::string(filePathBuf), "txt")) {174// is a script, since those dont exist normally, load them from "scripts/"175forceFolder = true;176Engine.usingDataFile = false;177addPath = true;178std::string fStr = std::string(filePathBuf);179fStr.erase(fStr.begin(), fStr.begin() + 5); // remove "Data/"180StrCopy(filePathBuf, fStr.c_str());181}182}183#endif184185#if RETRO_PLATFORM == RETRO_OSX || RETRO_PLATFORM == RETRO_ANDROID186#if RETRO_USE_MOD_LOADER187if (addPath) {188#else189if (true) {190#endif191char pathBuf[0x100];192sprintf(pathBuf, "%s/%s", gamePath, filePathBuf);193sprintf(filePathBuf, "%s", pathBuf);194}195#endif196197cFileHandle = NULL;198#if !RETRO_USE_ORIGINAL_CODE199StringLowerCase(fileInfo->fileName, filePath);200StrCopy(fileName, fileInfo->fileName);201202int fileIndex = CheckFileInfo(fileName);203if (fileIndex != -1 && !forceFolder) {204RSDKFileInfo *file = &rsdkContainer.files[fileIndex];205packID = file->packID;206cFileHandle = fOpen(rsdkContainer.packNames[file->packID], "rb");207if (cFileHandle) {208fSeek(cFileHandle, 0, SEEK_END);209fileSize = (int)fTell(cFileHandle);210211vFileSize = file->filesize;212virtualFileOffset = file->offset;213readPos = file->offset;214readSize = 0;215bufferPosition = 0;216fSeek(cFileHandle, virtualFileOffset, SEEK_SET);217218useEncryption = file->encrypted;219memset(fileInfo->encryptionStringA, 0, 0x10 * sizeof(byte));220memset(fileInfo->encryptionStringB, 0, 0x10 * sizeof(byte));221if (useEncryption) {222GenerateELoadKeys(vFileSize, (vFileSize >> 1) + 1);223eStringNo = (vFileSize & 0x1FC) >> 2;224eStringPosA = 0;225eStringPosB = 8;226eNybbleSwap = 0;227memcpy(fileInfo->encryptionStringA, encryptionStringA, 0x10 * sizeof(byte));228memcpy(fileInfo->encryptionStringB, encryptionStringB, 0x10 * sizeof(byte));229}230231fileInfo->readPos = readPos;232fileInfo->fileSize = fileSize;233fileInfo->vfileSize = vFileSize;234fileInfo->virtualFileOffset = virtualFileOffset;235fileInfo->eStringNo = eStringNo;236fileInfo->eStringPosB = eStringPosB;237fileInfo->eStringPosA = eStringPosA;238fileInfo->eNybbleSwap = eNybbleSwap;239fileInfo->bufferPosition = bufferPosition;240fileInfo->useEncryption = useEncryption;241fileInfo->packID = packID;242fileInfo->usingDataPack = true;243PrintLog("Loaded Data File '%s'", filePath);244245Engine.usingDataFile = true;246247return true;248}249#else250if (Engine.usingDataFile) {251StringLowerCase(fileInfo->fileName, filePath);252StrCopy(fileName, fileInfo->fileName);253uint hash[4];254int len = StrLength(fileInfo->fileName);255GenerateMD5FromString(fileInfo->fileName, len, &hash[0], &hash[1], &hash[2], &hash[3]);256257for (int f = 0; f < rsdkContainer.fileCount; ++f) {258RSDKFileInfo *file = &rsdkContainer.files[f];259260bool match = true;261for (int h = 0; h < 4; ++h) {262if (hash[h] != file->hash[h]) {263match = false;264break;265}266}267if (!match)268continue;269270packID = file->packID;271cFileHandle = fOpen(rsdkContainer.packNames[file->packID], "rb");272if (cFileHandle) {273fSeek(cFileHandle, 0, SEEK_END);274fileSize = (int)fTell(cFileHandle);275276vFileSize = file->filesize;277virtualFileOffset = file->offset;278readPos = file->offset;279readSize = 0;280bufferPosition = 0;281fSeek(cFileHandle, virtualFileOffset, SEEK_SET);282283useEncryption = file->encrypted;284memset(fileInfo->encryptionStringA, 0, 0x10 * sizeof(byte));285memset(fileInfo->encryptionStringB, 0, 0x10 * sizeof(byte));286if (useEncryption) {287GenerateELoadKeys(vFileSize, (vFileSize >> 1) + 1);288eStringNo = (vFileSize & 0x1FC) >> 2;289eStringPosA = 0;290eStringPosB = 8;291eNybbleSwap = 0;292memcpy(fileInfo->encryptionStringA, encryptionStringA, 0x10 * sizeof(byte));293memcpy(fileInfo->encryptionStringB, encryptionStringB, 0x10 * sizeof(byte));294}295296fileInfo->readPos = readPos;297fileInfo->fileSize = fileSize;298fileInfo->vfileSize = vFileSize;299fileInfo->virtualFileOffset = virtualFileOffset;300fileInfo->eStringNo = eStringNo;301fileInfo->eStringPosB = eStringPosB;302fileInfo->eStringPosA = eStringPosA;303fileInfo->eNybbleSwap = eNybbleSwap;304fileInfo->bufferPosition = bufferPosition;305fileInfo->useEncryption = useEncryption;306fileInfo->packID = packID;307fileInfo->usingDataPack = true;308PrintLog("Loaded Data File '%s'", filePath);309310return true;311}312else {313break;314}315}316#endif317PrintLog("Couldn't load file '%s'", filePath);318return false;319}320else {321StrCopy(fileInfo->fileName, filePathBuf);322StrCopy(fileName, fileInfo->fileName);323324cFileHandle = fOpen(fileInfo->fileName, "rb");325if (!cFileHandle) {326PrintLog("Couldn't load file '%s'", filePath);327return false;328}329virtualFileOffset = 0;330fSeek(cFileHandle, 0, SEEK_END);331fileInfo->fileSize = (int)fTell(cFileHandle);332fileSize = fileInfo->vfileSize = fileInfo->fileSize;333fSeek(cFileHandle, 0, SEEK_SET);334readPos = 0;335fileInfo->readPos = readPos;336packID = fileInfo->packID = -1;337fileInfo->usingDataPack = false;338bufferPosition = 0;339readSize = 0;340useEncryption = false;341342#if !RETRO_USE_ORIGINAL_CODE343Engine.usingDataFile = false;344#endif345346PrintLog("Loaded File '%s'", filePath);347return true;348}349}350351void GenerateELoadKeys(uint key1, uint key2)352{353char buffer[0x20];354uint hash[0x4];355356// StringA357ConvertIntegerToString(buffer, key1);358int len = StrLength(buffer);359GenerateMD5FromString(buffer, len, &hash[0], &hash[1], &hash[2], &hash[3]);360361#if !RETRO_USE_ORIGINAL_CODE362for (int i = 0; i < 4; ++i)363for (int j = 0; j < 4; ++j) encryptionStringA[i * 4 + j] = (hash[i] >> (8 * (j ^ 3))) & 0xFF;364#else365for (int y = 0; y < 0x10; y += 4) {366encryptionStringA[y + 3] = hash[y + 0];367encryptionStringA[y + 2] = hash[y + 1];368encryptionStringA[y + 1] = hash[y + 2];369encryptionStringA[y + 0] = hash[y + 3];370}371#endif372373// StringB374ConvertIntegerToString(buffer, key2);375len = StrLength(buffer);376GenerateMD5FromString(buffer, len, &hash[0], &hash[1], &hash[2], &hash[3]);377378#if !RETRO_USE_ORIGINAL_CODE379for (int i = 0; i < 4; ++i)380for (int j = 0; j < 4; ++j) encryptionStringB[i * 4 + j] = (hash[i] >> (8 * (j ^ 3))) & 0xFF;381#else382for (int y = 0; y < 0x10; y += 4) {383encryptionStringB[y + 3] = hash[y + 0];384encryptionStringB[y + 2] = hash[y + 1];385encryptionStringB[y + 1] = hash[y + 2];386encryptionStringB[y + 0] = hash[y + 3];387}388#endif389}390391const uint ENC_KEY_2 = 0x24924925;392const uint ENC_KEY_1 = 0xAAAAAAAB;393int mulUnsignedHigh(uint arg1, int arg2) { return (int)(((unsigned long long)arg1 * (unsigned long long)arg2) >> 32); }394395void FileRead(void *dest, int size)396{397byte *data = (byte *)dest;398memset(data, 0, size);399400if (readPos <= fileSize) {401if (useEncryption) {402while (size > 0) {403if (bufferPosition == readSize)404FillFileBuffer();405406*data = encryptionStringB[eStringPosB] ^ eStringNo ^ fileBuffer[bufferPosition++];407if (eNybbleSwap)408*data = ((*data << 4) + (*data >> 4)) & 0xFF;409*data ^= encryptionStringA[eStringPosA];410411++eStringPosA;412++eStringPosB;413if (eStringPosA <= 0x0F) {414if (eStringPosB > 0x0C) {415eStringPosB = 0;416eNybbleSwap ^= 0x01;417}418}419else if (eStringPosB <= 0x08) {420eStringPosA = 0;421eNybbleSwap ^= 0x01;422}423else {424eStringNo += 2;425eStringNo &= 0x7F;426427if (eNybbleSwap != 0) {428int key1 = mulUnsignedHigh(ENC_KEY_1, eStringNo);429int key2 = mulUnsignedHigh(ENC_KEY_2, eStringNo);430eNybbleSwap = 0;431432int temp1 = key2 + (eStringNo - key2) / 2;433int temp2 = key1 / 8 * 3;434435eStringPosA = eStringNo - temp1 / 4 * 7;436eStringPosB = eStringNo - temp2 * 4 + 2;437}438else {439int key1 = mulUnsignedHigh(ENC_KEY_1, eStringNo);440int key2 = mulUnsignedHigh(ENC_KEY_2, eStringNo);441eNybbleSwap = 1;442443int temp1 = key2 + (eStringNo - key2) / 2;444int temp2 = key1 / 8 * 3;445446eStringPosB = eStringNo - temp1 / 4 * 7;447eStringPosA = eStringNo - temp2 * 4 + 3;448}449}450451++data;452--size;453}454}455else {456while (size > 0) {457if (bufferPosition == readSize)458FillFileBuffer();459460*data++ = fileBuffer[bufferPosition++];461size--;462}463}464}465}466467void FileSkip(int count)468{469if (readPos <= fileSize) {470if (useEncryption) {471while (count > 0) {472if (bufferPosition == readSize)473FillFileBuffer();474bufferPosition++;475476++eStringPosA;477++eStringPosB;478if (eStringPosA <= 0x0F) {479if (eStringPosB > 0x0C) {480eStringPosB = 0;481eNybbleSwap ^= 0x01;482}483}484else if (eStringPosB <= 0x08) {485eStringPosA = 0;486eNybbleSwap ^= 0x01;487}488else {489eStringNo += 2;490eStringNo &= 0x7F;491492if (eNybbleSwap != 0) {493int key1 = mulUnsignedHigh(ENC_KEY_1, eStringNo);494int key2 = mulUnsignedHigh(ENC_KEY_2, eStringNo);495eNybbleSwap = 0;496497int temp1 = key2 + (eStringNo - key2) / 2;498int temp2 = key1 / 8 * 3;499500eStringPosA = eStringNo - temp1 / 4 * 7;501eStringPosB = eStringNo - temp2 * 4 + 2;502}503else {504int key1 = mulUnsignedHigh(ENC_KEY_1, eStringNo);505int key2 = mulUnsignedHigh(ENC_KEY_2, eStringNo);506eNybbleSwap = 1;507508int temp1 = key2 + (eStringNo - key2) / 2;509int temp2 = key1 / 8 * 3;510511eStringPosB = eStringNo - temp1 / 4 * 7;512eStringPosA = eStringNo - temp2 * 4 + 3;513}514}515516--count;517}518}519else {520while (count > 0) {521if (bufferPosition == readSize)522FillFileBuffer();523bufferPosition++;524count--;525}526}527}528}529530void GetFileInfo(FileInfo *fileInfo)531{532StrCopy(fileInfo->fileName, fileName);533fileInfo->bufferPosition = bufferPosition;534fileInfo->readPos = readPos - readSize;535fileInfo->fileSize = fileSize;536fileInfo->vfileSize = vFileSize;537fileInfo->virtualFileOffset = virtualFileOffset;538fileInfo->eStringPosA = eStringPosA;539fileInfo->eStringPosB = eStringPosB;540fileInfo->eStringNo = eStringNo;541fileInfo->eNybbleSwap = eNybbleSwap;542fileInfo->useEncryption = useEncryption;543fileInfo->packID = packID;544fileInfo->usingDataPack = Engine.usingDataFile;545memcpy(encryptionStringA, fileInfo->encryptionStringA, 0x10 * sizeof(byte));546memcpy(encryptionStringB, fileInfo->encryptionStringB, 0x10 * sizeof(byte));547}548549void SetFileInfo(FileInfo *fileInfo)550{551#if !RETRO_USE_ORIGINAL_CODE552if (fileInfo->usingDataPack) {553#else554if (Engine.usingDataFile) {555#endif556cFileHandle = fOpen(rsdkContainer.packNames[fileInfo->packID], "rb");557if (cFileHandle) {558virtualFileOffset = fileInfo->virtualFileOffset;559vFileSize = fileInfo->vfileSize;560fSeek(cFileHandle, 0, SEEK_END);561fileSize = (int)fTell(cFileHandle);562readPos = fileInfo->readPos;563fSeek(cFileHandle, readPos, SEEK_SET);564FillFileBuffer();565bufferPosition = fileInfo->bufferPosition;566eStringPosA = fileInfo->eStringPosA;567eStringPosB = fileInfo->eStringPosB;568eStringNo = fileInfo->eStringNo;569eNybbleSwap = fileInfo->eNybbleSwap;570useEncryption = fileInfo->useEncryption;571packID = fileInfo->packID;572Engine.usingDataFile = fileInfo->usingDataPack;573574if (useEncryption) {575GenerateELoadKeys(vFileSize, (vFileSize >> 1) + 1);576}577}578}579else {580StrCopy(fileName, fileInfo->fileName);581cFileHandle = fOpen(fileInfo->fileName, "rb");582virtualFileOffset = 0;583fileSize = fileInfo->fileSize;584readPos = fileInfo->readPos;585fSeek(cFileHandle, readPos, SEEK_SET);586FillFileBuffer();587bufferPosition = fileInfo->bufferPosition;588eStringPosA = 0;589eStringPosB = 0;590eStringNo = 0;591eNybbleSwap = 0;592useEncryption = fileInfo->useEncryption;593packID = fileInfo->packID;594Engine.usingDataFile = fileInfo->usingDataPack;595}596}597598size_t GetFilePosition()599{600if (Engine.usingDataFile)601return bufferPosition + readPos - readSize - virtualFileOffset;602else603return bufferPosition + readPos - readSize;604}605606void SetFilePosition(int newPos)607{608if (useEncryption) {609readPos = virtualFileOffset + newPos;610eStringNo = (vFileSize & 0x1FC) >> 2;611eStringPosA = 0;612eStringPosB = 8;613eNybbleSwap = false;614while (newPos) {615++eStringPosA;616++eStringPosB;617if (eStringPosA <= 0x0F) {618if (eStringPosB > 0x0C) {619eStringPosB = 0;620eNybbleSwap ^= 0x01;621}622}623else if (eStringPosB <= 0x08) {624eStringPosA = 0;625eNybbleSwap ^= 0x01;626}627else {628eStringNo += 2;629eStringNo &= 0x7F;630631if (eNybbleSwap != 0) {632int key1 = mulUnsignedHigh(ENC_KEY_1, eStringNo);633int key2 = mulUnsignedHigh(ENC_KEY_2, eStringNo);634eNybbleSwap = 0;635636int temp1 = key2 + (eStringNo - key2) / 2;637int temp2 = key1 / 8 * 3;638639eStringPosA = eStringNo - temp1 / 4 * 7;640eStringPosB = eStringNo - temp2 * 4 + 2;641}642else {643int key1 = mulUnsignedHigh(ENC_KEY_1, eStringNo);644int key2 = mulUnsignedHigh(ENC_KEY_2, eStringNo);645eNybbleSwap = 1;646647int temp1 = key2 + (eStringNo - key2) / 2;648int temp2 = key1 / 8 * 3;649650eStringPosB = eStringNo - temp1 / 4 * 7;651eStringPosA = eStringNo - temp2 * 4 + 3;652}653}654--newPos;655}656}657else {658if (Engine.usingDataFile)659readPos = virtualFileOffset + newPos;660else661readPos = newPos;662}663fSeek(cFileHandle, readPos, SEEK_SET);664FillFileBuffer();665}666667bool ReachedEndOfFile()668{669if (Engine.usingDataFile)670return bufferPosition + readPos - readSize - virtualFileOffset >= vFileSize;671else672return bufferPosition + readPos - readSize >= fileSize;673}674675676