Path: blob/main/RSDKv4/String.cpp
817 views
#include "RetroEngine.hpp"12ushort *strPressStart = NULL;3ushort *strTouchToStart = NULL;4ushort *strStartGame = NULL;5ushort *strTimeAttack = NULL;6ushort *strAchievements = NULL;7ushort *strLeaderboards = NULL;8ushort *strHelpAndOptions = NULL;9ushort *strSoundTest = NULL;10ushort *str2PlayerVS = NULL;11ushort *strSaveSelect = NULL;12ushort *strPlayerSelect = NULL;13ushort *strNoSave = NULL;14ushort *strNewGame = NULL;15ushort *strDelete = NULL;16ushort *strDeleteMessage = NULL;17ushort *strYes = NULL;18ushort *strNo = NULL;19ushort *strSonic = NULL;20ushort *strTails = NULL;21ushort *strKnuckles = NULL;22ushort *strPause = NULL;23ushort *strContinue = NULL;24ushort *strRestart = NULL;25ushort *strExit = NULL;26ushort *strDevMenu = NULL;27ushort *strRestartMessage = NULL;28ushort *strExitMessage = NULL;29ushort *strNSRestartMessage = NULL;30ushort *strNSExitMessage = NULL;31ushort *strExitGame = NULL;32ushort *strNetworkMessage = NULL;33ushort *strStageList[16];34ushort *strSaveStageList[32];35ushort *strNewBestTime = NULL;36ushort *strRecords = NULL;37ushort *strNextAct = NULL;38ushort *strPlay = NULL;39ushort *strTotalTime = NULL;40ushort *strInstructions = NULL;41ushort *strSettings = NULL;42ushort *strStaffCredits = NULL;43ushort *strAbout = NULL;44ushort *strMusic = NULL;45ushort *strSoundFX = NULL;46ushort *strSpindash = NULL;47ushort *strBoxArt = NULL;48ushort *strControls = NULL;49ushort *strOn = NULL;50ushort *strOff = NULL;51ushort *strCustomizeDPad = NULL;52ushort *strDPadSize = NULL;53ushort *strDPadOpacity = NULL;54ushort *strHelpText1 = NULL;55ushort *strHelpText2 = NULL;56ushort *strHelpText3 = NULL;57ushort *strHelpText4 = NULL;58ushort *strHelpText5 = NULL;59ushort *strVersionName = NULL;60ushort *strPrivacy = NULL;61ushort *strTerms = NULL;6263int stageStrCount = 0;6465ushort stringStorage[STRSTORAGE_SIZE * STRING_SIZE];66int stringStorePos = 0;6768int creditsListSize = 0;69ushort *strCreditsList[CREDITS_LIST_COUNT];70byte creditsType[CREDITS_LIST_COUNT];71float creditsAdvanceY[CREDITS_LIST_COUNT];7273#include <string.h>7475int FindStringToken(const char *string, const char *token, char stopID)76{77int tokenCharID = 0;78bool tokenMatch = true;79int stringCharID = 0;80int foundTokenID = 0;8182while (string[stringCharID]) {83tokenCharID = 0;84tokenMatch = true;85while (token[tokenCharID]) {86if (!string[tokenCharID + stringCharID])87return -1;8889if (string[tokenCharID + stringCharID] != token[tokenCharID])90tokenMatch = false;9192++tokenCharID;93}94if (tokenMatch && ++foundTokenID == stopID)95return stringCharID;9697++stringCharID;98}99return -1;100}101102int FindLastStringToken(const char *string, const char *token)103{104int tokenCharID = 0;105bool tokenMatch = true;106int stringCharID = 0;107int foundTokenID = 0;108int lastResult = -1;109110while (string[stringCharID]) {111tokenCharID = 0;112tokenMatch = true;113while (token[tokenCharID]) {114if (!string[tokenCharID + stringCharID])115return lastResult;116117if (string[tokenCharID + stringCharID] != token[tokenCharID])118tokenMatch = false;119120++tokenCharID;121}122if (tokenMatch)123lastResult = stringCharID;124125++stringCharID;126}127return lastResult;128}129130int FindStringTokenUnicode(const ushort *string, const ushort *token, char stopID)131{132int tokenCharID = 0;133bool tokenMatch = true;134int stringCharID = 0;135int foundTokenID = 0;136137while (string[stringCharID]) {138tokenCharID = 0;139tokenMatch = true;140while (token[tokenCharID]) {141if (!string[tokenCharID + stringCharID])142return -1;143144if (string[tokenCharID + stringCharID] != token[tokenCharID])145tokenMatch = false;146147++tokenCharID;148}149if (tokenMatch && ++foundTokenID == stopID)150return stringCharID;151152++stringCharID;153}154return -1;155}156157void ConvertIntegerToString(char *text, int value) { sprintf(text, "%d", value); }158159void GenerateMD5FromString(const char *string, int len, uint *hash0, uint *hash1, uint *hash2, uint *hash3)160{161#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))162163static const uint K[64] = {1640xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a,1650xa8304613, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,1660x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 0xf61e2562, 0xc040b340,1670x265e5a51, 0xe9b6c7aa, 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,1680x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 0xa9e3e905, 0xfcefa3f8,1690x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,1700xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa,1710xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,1720xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92,1730xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,1740xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391};175176static const uint S[64] = {1777, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,1785, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,1794, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,1806, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21};181182static byte hashStream[0x400];183184*hash0 = 0x67452301;185*hash1 = 0xefcdab89;186*hash2 = 0x98badcfe;187*hash3 = 0x10325476;188memset(hashStream, 0, 0x400);189190uint length_bits = len * 8;191int padded_length = length_bits + 1;192while (padded_length % 512 != 448) {193padded_length++;194}195196memcpy(hashStream, string, len);197198padded_length /= 8;199// Padding (only 0x80 is needed since memset(0) has been called on hashStream)200hashStream[len] = 0x80;201// Write length in little endian order202for (int p = 0; p < 4; ++p) hashStream[padded_length + p] = (length_bits >> (8 * p));203204// Process blocks205for (int block = 0; block < padded_length; block += 64) {206uint A = *hash0;207uint B = *hash1;208uint C = *hash2;209uint D = *hash3;210for (int i = 0; i < 64; ++i) {211uint res, idx;212if (i < 0x10) {213res = (B & C) | ((~B) & D);214idx = i;215} else if (i < 0x20) {216res = (D & B) | ((~D) & C);217idx = ((5 * i) + 1) % 16;218} else if (i < 0x30) {219res = B ^ C ^ D;220idx = ((3 * i) + 5) % 16;221} else {222res = C ^ (B | (~D));223idx = (7 * i) % 16;224}225uint streamVal = 0;226// Convert to little endian227for (int p = 0; p < 4; ++p) streamVal |= (hashStream[block + (idx * 4) + p] & 0xFF) << (8 * p);228uint temp = D;229D = C;230C = B;231B = B + ROTATE_LEFT((A + res + K[i] + streamVal), S[i]);232A = temp;233}234*hash0 += A;235*hash1 += B;236*hash2 += C;237*hash3 += D;238}239}240241void InitLocalizedStrings()242{243memset(stringStorage, 0, STRING_SIZE * STRSTORAGE_SIZE * sizeof(ushort));244stringStorePos = 0;245246char langStr[0x4];247switch (Engine.language) {248case RETRO_EN: StrCopy(langStr, "en"); break;249case RETRO_FR: StrCopy(langStr, "fr"); break;250case RETRO_IT: StrCopy(langStr, "it"); break;251case RETRO_DE: StrCopy(langStr, "de"); break;252case RETRO_ES: StrCopy(langStr, "es"); break;253case RETRO_JP: StrCopy(langStr, "ja"); break;254case RETRO_PT: StrCopy(langStr, "pt"); break;255case RETRO_RU: StrCopy(langStr, "ru"); break;256case RETRO_KO: StrCopy(langStr, "ko"); break;257case RETRO_ZH: StrCopy(langStr, "zh"); break;258case RETRO_ZS: StrCopy(langStr, "zs"); break;259default: break;260}261strPressStart = ReadLocalizedString("PressStart", langStr, "Data/Game/StringList.txt");262strTouchToStart = ReadLocalizedString("TouchToStart", langStr, "Data/Game/StringList.txt");263strStartGame = ReadLocalizedString("StartGame", langStr, "Data/Game/StringList.txt");264strTimeAttack = ReadLocalizedString("TimeAttack", langStr, "Data/Game/StringList.txt");265strAchievements = ReadLocalizedString("Achievements", langStr, "Data/Game/StringList.txt");266strLeaderboards = ReadLocalizedString("Leaderboards", langStr, "Data/Game/StringList.txt");267strHelpAndOptions = ReadLocalizedString("HelpAndOptions", langStr, "Data/Game/StringList.txt");268269// SoundTest & StageTest, both unused270strSoundTest = ReadLocalizedString("SoundTest", langStr, "Data/Game/StringList.txt");271// strStageTest = ReadLocalizedString("StageTest", langStr, "Data/Game/StringList.txt");272273str2PlayerVS = ReadLocalizedString("TwoPlayerVS", langStr, "Data/Game/StringList.txt");274strSaveSelect = ReadLocalizedString("SaveSelect", langStr, "Data/Game/StringList.txt");275strPlayerSelect = ReadLocalizedString("PlayerSelect", langStr, "Data/Game/StringList.txt");276strNoSave = ReadLocalizedString("NoSave", langStr, "Data/Game/StringList.txt");277strNewGame = ReadLocalizedString("NewGame", langStr, "Data/Game/StringList.txt");278strDelete = ReadLocalizedString("Delete", langStr, "Data/Game/StringList.txt");279strDeleteMessage = ReadLocalizedString("DeleteSavedGame", langStr, "Data/Game/StringList.txt");280strYes = ReadLocalizedString("Yes", langStr, "Data/Game/StringList.txt");281strNo = ReadLocalizedString("No", langStr, "Data/Game/StringList.txt");282strSonic = ReadLocalizedString("Sonic", langStr, "Data/Game/StringList.txt");283strTails = ReadLocalizedString("Tails", langStr, "Data/Game/StringList.txt");284strKnuckles = ReadLocalizedString("Knuckles", langStr, "Data/Game/StringList.txt");285strPause = ReadLocalizedString("Pause", langStr, "Data/Game/StringList.txt");286strContinue = ReadLocalizedString("Continue", langStr, "Data/Game/StringList.txt");287strRestart = ReadLocalizedString("Restart", langStr, "Data/Game/StringList.txt");288strExit = ReadLocalizedString("Exit", langStr, "Data/Game/StringList.txt");289strDevMenu = ReadLocalizedString("DevMenu", "en", "Data/Game/StringList.txt");290strRestartMessage = ReadLocalizedString("RestartMessage", langStr, "Data/Game/StringList.txt");291strExitMessage = ReadLocalizedString("ExitMessage", langStr, "Data/Game/StringList.txt");292if (Engine.language == RETRO_JP) {293strNSRestartMessage = ReadLocalizedString("NSRestartMessage", "ja", "Data/Game/StringList.txt");294strNSExitMessage = ReadLocalizedString("NSExitMessage", "ja", "Data/Game/StringList.txt");295}296else {297strNSRestartMessage = ReadLocalizedString("RestartMessage", langStr, "Data/Game/StringList.txt");298strNSExitMessage = ReadLocalizedString("ExitMessage", langStr, "Data/Game/StringList.txt");299}300strExitGame = ReadLocalizedString("ExitGame", langStr, "Data/Game/StringList.txt");301strNetworkMessage = ReadLocalizedString("NetworkMessage", langStr, "Data/Game/StringList.txt");302for (int i = 0; i < 16; ++i) {303char buffer[0x10];304sprintf(buffer, "StageName%d", i + 1);305306strStageList[i] = ReadLocalizedString(buffer, "en", "Data/Game/StringList.txt");307}308309stageStrCount = 0;310for (int i = 0; i < 32; ++i) {311char buffer[0x20];312sprintf(buffer, "SaveStageName%d", i + 1);313314strSaveStageList[i] = ReadLocalizedString(buffer, "en", "Data/Game/StringList.txt");315if (!strSaveStageList[i])316break;317stageStrCount++;318}319strNewBestTime = ReadLocalizedString("NewBestTime", langStr, "Data/Game/StringList.txt");320strRecords = ReadLocalizedString("Records", langStr, "Data/Game/StringList.txt");321strNextAct = ReadLocalizedString("NextAct", langStr, "Data/Game/StringList.txt");322strPlay = ReadLocalizedString("Play", langStr, "Data/Game/StringList.txt");323strTotalTime = ReadLocalizedString("TotalTime", langStr, "Data/Game/StringList.txt");324strInstructions = ReadLocalizedString("Instructions", langStr, "Data/Game/StringList.txt");325strSettings = ReadLocalizedString("Settings", langStr, "Data/Game/StringList.txt");326strStaffCredits = ReadLocalizedString("StaffCredits", langStr, "Data/Game/StringList.txt");327strAbout = ReadLocalizedString("About", langStr, "Data/Game/StringList.txt");328strMusic = ReadLocalizedString("Music", langStr, "Data/Game/StringList.txt");329strSoundFX = ReadLocalizedString("SoundFX", langStr, "Data/Game/StringList.txt");330strSpindash = ReadLocalizedString("SpinDash", langStr, "Data/Game/StringList.txt");331strBoxArt = ReadLocalizedString("BoxArt", langStr, "Data/Game/StringList.txt");332strControls = ReadLocalizedString("Controls", langStr, "Data/Game/StringList.txt");333strOn = ReadLocalizedString("On", langStr, "Data/Game/StringList.txt");334strOff = ReadLocalizedString("Off", langStr, "Data/Game/StringList.txt");335strCustomizeDPad = ReadLocalizedString("CustomizeDPad", langStr, "Data/Game/StringList.txt");336strDPadSize = ReadLocalizedString("DPadSize", langStr, "Data/Game/StringList.txt");337strDPadOpacity = ReadLocalizedString("DPadOpacity", langStr, "Data/Game/StringList.txt");338strHelpText1 = ReadLocalizedString("HelpText1", langStr, "Data/Game/StringList.txt");339strHelpText2 = ReadLocalizedString("HelpText2", langStr, "Data/Game/StringList.txt");340strHelpText3 = ReadLocalizedString("HelpText3", langStr, "Data/Game/StringList.txt");341strHelpText4 = ReadLocalizedString("HelpText4", langStr, "Data/Game/StringList.txt");342strHelpText5 = ReadLocalizedString("HelpText5", langStr, "Data/Game/StringList.txt");343strVersionName = ReadLocalizedString("Version", langStr, "Data/Game/StringList.txt");344strPrivacy = ReadLocalizedString("Privacy", langStr, "Data/Game/StringList.txt");345strTerms = ReadLocalizedString("Terms", langStr, "Data/Game/StringList.txt");346// strMoreGames = ReadLocalizedString("MoreGames", langStr, "Data/Game/StringList.txt");347348// Video Filter options349// strVideoFilter = ReadLocalizedString("VideoFilter", langStr, "Data/Game/StringList.txt");350// strSharp = ReadLocalizedString("Sharp", langStr, "Data/Game/StringList.txt");351// strSmooth = ReadLocalizedString("Smooth", langStr, "Data/Game/StringList.txt");352// strNostalgic = ReadLocalizedString("Nostalgic", langStr, "Data/Game/StringList.txt");353354// Login With Facebook355// strFBLogin = ReadLocalizedString("LoginWithFacebook", langStr, "Data/Game/StringList.txt");356357// Unused Control Modes358// strControlMethod = ReadLocalizedString("ControlMethod", langStr, "Data/Game/StringList.txt");359// strSwipeAndTap = ReadLocalizedString("SwipeAndTap", langStr, "Data/Game/StringList.txt");360// strVirtualDPad = ReadLocalizedString("VirtualDPad", langStr, "Data/Game/StringList.txt");361362ReadCreditsList("Data/Game/CreditsMobile.txt");363}364ushort *ReadLocalizedString(const char *stringName, const char *language, const char *filePath)365{366FileInfo info;367ushort strName[0x40];368ushort langName[0x8];369ushort lineBuffer[0x200];370371memset(strName, 0, 0x40 * sizeof(ushort));372memset(langName, 0, 0x8 * sizeof(ushort));373memset(lineBuffer, 0, 0x200 * sizeof(ushort));374375int strNamePos = 0;376while (stringName[strNamePos]) {377strName[strNamePos] = stringName[strNamePos];378strNamePos++;379}380strName[strNamePos++] = ':';381strName[strNamePos] = 0;382383int langNamePos = 0;384for (langNamePos = 0; langNamePos < 4; ++langNamePos) {385if (!language[langNamePos])386break;387else388langName[langNamePos] = language[langNamePos];389}390391langName[langNamePos++] = ':';392langName[langNamePos] = 0;393394if (LoadFile(filePath, &info)) {395int readMode = 0;396ushort curChar = 0;397int charID = 0;398byte flag = 0;399while (!ReachedEndOfFile()) {400switch (readMode) {401case 0:402ReadStringLineUnicode(lineBuffer);403if (!FindStringTokenUnicode(lineBuffer, langName, 1)) {404int tPos = FindStringTokenUnicode(lineBuffer, strName, 1);405if (tPos == 3)406flag = true;407readMode = tPos == 3;408}409break;410case 1:411FileRead(fileBuffer, sizeof(ushort));412curChar = fileBuffer[0] + (fileBuffer[1] << 8);413if (curChar > '\n' && curChar != '\r') {414stringStorage[stringStorePos + charID++] = 0;415CloseFile();416417int pos = stringStorePos;418stringStorePos += charID;419return &stringStorage[pos];420}421else if (curChar == '\t') {422if (flag) {423flag = true;424readMode = 2;425}426else {427readMode = 2;428stringStorage[stringStorePos + charID++] = '\n';429}430}431break;432case 2:433FileRead(fileBuffer, sizeof(ushort));434curChar = fileBuffer[0] + (fileBuffer[1] << 8);435if (curChar != '\t') {436stringStorage[stringStorePos + charID++] = curChar;437if (curChar == '\r' || curChar == '\n') {438flag = false;439readMode = 1;440}441}442break;443}444}445CloseFile();446}447448PrintLog("Failed to load string... (%s, %s)", language, stringName);449return NULL;450}451452void ReadCreditsList(const char *filePath)453{454FileInfo info;455if (LoadFile(filePath, &info)) {456creditsListSize = 0;457458char dest[0x100];459float advance = 24.0;460if (!ReachedEndOfFile()) {461while (creditsListSize < CREDITS_LIST_COUNT) {462ReadCreditsLine(dest);463464if (dest[0] != '[' || dest[2] != ']') {465advance += 24.0;466}467else {468int strPos = 0;469char curChar = dest[strPos + 3];470while (curChar) {471stringStorage[stringStorePos + strPos] = curChar;472strPos++;473curChar = dest[strPos + 3];474}475stringStorage[stringStorePos + strPos++] = 0;476477switch (dest[1]) {478default:479case '0': creditsType[creditsListSize] = 0; break;480case '1': creditsType[creditsListSize] = 1; break;481case '2': creditsType[creditsListSize] = 2; break;482case '3': creditsType[creditsListSize] = 3; break;483}484485creditsAdvanceY[creditsListSize] = advance;486487strCreditsList[creditsListSize++] = &stringStorage[stringStorePos];488stringStorePos += strPos;489advance = 24.0;490}491492if (ReachedEndOfFile())493break;494}495}496497CloseFile();498}499}500501502