Path: blob/master/RSDKv5/RSDK/User/Core/UserStorage.cpp
1162 views
#include "RSDK/Core/RetroEngine.hpp"12#if RETRO_REV0234// ====================5// API Cores6// ====================78namespace RSDK9{10namespace SKU11{1213// Dummy API14#if RETRO_USERCORE_DUMMY15#include "RSDK/User/Dummy/DummyStorage.cpp"16#endif1718// Steam API19#if RETRO_USERCORE_STEAM20#include "RSDK/User/Steam/SteamStorage.cpp"21#endif2223// Epic Games API24#if RETRO_USERCORE_EOS25#include "RSDK/User/EOS/EOSStorage.cpp"26#endif2728// Switch API29#if RETRO_USERCORE_NX30#include "RSDK/User/NX/NXStorage.cpp"31#endif3233} // namespace SKU34} // namespace RSDK3536using namespace RSDK;3738RSDK::SKU::UserStorage *RSDK::SKU::userStorage = NULL;39RSDK::SKU::UserDBStorage *RSDK::SKU::userDBStorage = NULL;4041// =======================42// USER DB VALUE43// =======================44bool32 RSDK::SKU::UserDBValue::CheckMatch(int32 row, int32 column)45{46UserDB *userDB = (UserDB *)parent;47UserDBValue *other = &userDB->rows[row].values[column];4849switch (userDB->columnTypes[column]) {50case DBVAR_BOOL:51case DBVAR_UINT8:52case DBVAR_INT8: return memcmp(data, other->data, sizeof(int8)) == 0;5354case DBVAR_UINT16:55case DBVAR_INT16: return memcmp(data, other->data, sizeof(int16)) == 0;5657case DBVAR_UINT32:58case DBVAR_INT32:59case DBVAR_FLOAT:60case DBVAR_COLOR: return memcmp(data, other->data, sizeof(int32)) == 0;6162case DBVAR_STRING: {63char *thisString = (char *)data;64char *otherString = (char *)other->data;6566return strcmp(thisString, otherString) == 0;67}68default: break;69}7071return false;72}73void RSDK::SKU::UserDBValue::Set(int32 type, void *data)74{75size = 0;76memset(this->data, 0, sizeof(this->data));77if (data) {78switch (type) {79case DBVAR_BOOL:80case DBVAR_UINT8:81case DBVAR_INT8:82size = sizeof(int8);83memcpy(this->data, data, sizeof(int8));84break;8586case DBVAR_UINT16:87case DBVAR_INT16:88size = sizeof(int16);89memcpy(this->data, data, sizeof(int16));90break;9192case DBVAR_UINT32:93case DBVAR_INT32:94case DBVAR_FLOAT:95case DBVAR_COLOR:96size = sizeof(int32);97memcpy(this->data, data, sizeof(int32));98break;99100case DBVAR_STRING: {101char *string = (char *)data;102103int32 len = (int32)strlen(string);104for (int32 c = 0; c < len && c < 15; ++c) {105this->data[c] = string[c];106}107break;108}109110default: break;111}112}113}114void RSDK::SKU::UserDBValue::Get(int32 type, void *data)115{116int8 *outData = (int8 *)data;117switch (type) {118case DBVAR_BOOL:119case DBVAR_UINT8:120case DBVAR_INT8: memcpy(outData, this->data, sizeof(int8)); break;121122case DBVAR_UINT16:123case DBVAR_INT16: memcpy(outData, this->data, sizeof(int16)); break;124125case DBVAR_UINT32:126case DBVAR_INT32:127case DBVAR_FLOAT:128case DBVAR_COLOR: memcpy(outData, this->data, sizeof(int32)); break;129130case DBVAR_STRING: {131memset(outData, 0, size + 1);132char *string = (char *)this->data;133for (int32 c = 0; c < size; ++c) {134outData[c] = string[c];135}136break;137}138139default: break;140}141}142143// =======================144// USER DB ROW145// =======================146bool32 RSDK::SKU::UserDBRow::AddValue(int32 type, char *name, void *value)147{148UserDB *userDB = parent;149uint32 uuid = 0;150GenerateHashCRC(&uuid, name);151152for (int32 c = 0; c < userDB->columnCount; ++c) {153if (userDB->columnUUIDs[c] == uuid) {154if (c < 0 || type != userDB->columnTypes[c])155return false;156157values[c].Set(type, value);158159time_t t;160time(&t);161changeTime = *localtime(&t);162return true;163}164}165166return false;167}168bool32 RSDK::SKU::UserDBRow::GetValue(int32 type, char *name, void *value)169{170UserDB *userDB = parent;171uint32 uuid = 0;172GenerateHashCRC(&uuid, name);173174for (int32 c = 0; c < userDB->columnCount; ++c) {175if (userDB->columnUUIDs[c] == uuid) {176if (c < 0 || type != userDB->columnTypes[c])177return false;178179values[c].Get(type, value);180return true;181}182}183184return false;185}186187bool32 RSDK::SKU::UserDBRow::Compare(UserDBRow *other, int32 type, char *name, bool32 sortAscending)188{189uint8 thisData[0x10];190uint8 otherData[0x10];191memset(thisData, 0, sizeof(thisData));192memset(otherData, 0, sizeof(otherData));193194this->GetValue(type, name, thisData);195other->GetValue(type, name, otherData);196switch (type) {197case DBVAR_BOOL:198case DBVAR_UINT8: {199uint8 thisValue = 0, otherValue = 0;200memcpy(&thisValue, thisData, sizeof(uint8));201memcpy(&otherValue, otherData, sizeof(uint8));202203if (!sortAscending)204return thisValue > otherValue;205else206return thisValue < otherValue;207break;208}209210case DBVAR_INT8: {211int8 thisValue = 0, otherValue = 0;212memcpy(&thisValue, thisData, sizeof(int8));213memcpy(&otherValue, otherData, sizeof(int8));214215if (!sortAscending)216return thisValue > otherValue;217else218return thisValue < otherValue;219break;220}221222case DBVAR_UINT16: {223uint16 thisValue = 0, otherValue = 0;224memcpy(&thisValue, thisData, sizeof(uint16));225memcpy(&otherValue, otherData, sizeof(uint16));226227if (!sortAscending)228return thisValue > otherValue;229else230return thisValue < otherValue;231break;232}233234case DBVAR_INT16: {235int16 thisValue = 0, otherValue = 0;236memcpy(&thisValue, thisData, sizeof(int16));237memcpy(&otherValue, otherData, sizeof(int16));238239if (!sortAscending)240return thisValue > otherValue;241else242return thisValue < otherValue;243break;244}245246case DBVAR_UINT32:247case DBVAR_COLOR: {248uint32 thisValue = 0, otherValue = 0;249memcpy(&thisValue, thisData, sizeof(uint32));250memcpy(&otherValue, otherData, sizeof(uint32));251252if (!sortAscending)253return thisValue > otherValue;254else255return thisValue < otherValue;256break;257}258259case DBVAR_INT32: {260int32 thisValue = 0, otherValue = 0;261memcpy(&thisValue, thisData, sizeof(int32));262memcpy(&otherValue, otherData, sizeof(int32));263264if (!sortAscending)265return thisValue > otherValue;266else267return thisValue < otherValue;268break;269}270271case DBVAR_FLOAT: {272float thisValue = 0, otherValue = 0;273memcpy(&thisValue, thisData, sizeof(float));274memcpy(&otherValue, otherData, sizeof(float));275276if (!sortAscending)277return thisValue > otherValue;278else279return thisValue < otherValue;280break;281}282283case DBVAR_STRING: {284char *thisString = (char *)thisData;285char *otherString = (char *)otherData;286287int32 result = strcmp(thisString, otherString);288if (sortAscending)289return result > 0 ? true : false;290else291return result < 0 ? true : false;292break;293}294default: break;295}296return false;297}298299// =======================300// USER DB301// =======================302void RSDK::SKU::UserDB::Init(va_list list)303{304int32 cnt = 0;305while (true) {306int32 type = va_arg(list, int32);307if (!type)308break;309310columnTypes[cnt] = type;311memset(columnNames[cnt], 0, 0x10);312sprintf_s(columnNames[cnt], sizeof(columnNames[cnt]), "%s", va_arg(list, const char *));313GenerateHashCRC(&columnUUIDs[cnt], columnNames[cnt]);314++cnt;315}316317columnCount = cnt;318rowCount = 0;319memset(rows, 0, sizeof(rows));320Refresh();321active = true;322valid = true;323}324bool32 RSDK::SKU::UserDB::Load(uint8 *buffer)325{326uint32 signature = *(uint32 *)buffer;327if (signature != RETRO_USERDB_SIGNATURE)328return false;329330buffer += sizeof(int32);331buffer += sizeof(int32); // used size332333rowCount = *(uint16 *)buffer;334buffer += sizeof(uint16);335336columnCount = *buffer;337buffer++;338339for (int32 c = 0; c < columnCount; ++c) {340columnTypes[c] = *buffer;341buffer++;342343sprintf_s(columnNames[c], sizeof(columnNames[c]), "%s", (char *)buffer);344buffer += 0x10;345346GenerateHashCRC(&columnUUIDs[c], columnNames[c]);347}348349for (int32 r = 0; r < rowCount; ++r) {350rows[r].uuid = *(uint32 *)buffer;351buffer += sizeof(uint32);352353memcpy(&rows[r].createTime, buffer, sizeof(tm));354buffer += sizeof(tm);355memcpy(&rows[r].changeTime, buffer, sizeof(tm));356buffer += sizeof(tm);357358for (int32 c = 0; c < columnCount; ++c) {359rows[r].values[c].size = *buffer;360buffer++;361362memcpy(&rows[r].values[c].data, buffer, rows[r].values[c].size);363buffer += rows[r].values[c].size;364}365}366367active = true;368Refresh();369return true;370}371void RSDK::SKU::UserDB::Save(int32 totalSize, uint8 *buffer)372{373int32 size = 0;374if (sizeof(uint32) < totalSize) {375size = sizeof(uint32);376*(uint32 *)buffer = RETRO_USERDB_SIGNATURE;377buffer += sizeof(uint32);378}379380if (size + sizeof(uint32) < totalSize) {381size += sizeof(uint32);382*(uint32 *)buffer = (int32)GetSize(); // used size383buffer += sizeof(uint32);384}385386if (size + sizeof(uint16) < totalSize) {387size += sizeof(uint16);388*(uint16 *)buffer = rowCount;389buffer += sizeof(uint16);390}391392if (size + sizeof(uint8) < totalSize) {393++size;394*buffer++ = columnCount;395}396397for (int32 c = 0; c < columnCount; ++c) {398if (size + sizeof(uint8) < totalSize) {399++size;400*buffer++ = (uint8)columnTypes[c];401}402if (size + 0x10 * sizeof(uint8) < totalSize) {403memset(buffer, 0, 0x10 * sizeof(uint8));404sprintf_s((char *)buffer, sizeof(columnNames[c]), "%s", columnNames[c]);405size += 0x10;406buffer += 0x10;407}408}409410for (int32 r = 0; r < rowCount; ++r) {411if (size + sizeof(uint32) < totalSize) {412size += sizeof(uint32);413*(uint32 *)buffer = rows[r].uuid;414buffer += sizeof(uint32);415}416if (size + sizeof(tm) < totalSize) {417memcpy(buffer, &rows[r].createTime, sizeof(tm));418size += sizeof(tm);419buffer += sizeof(tm);420}421if (size + sizeof(tm) < totalSize) {422memcpy(buffer, &rows[r].changeTime, sizeof(tm));423size += sizeof(tm);424buffer += sizeof(tm);425}426427for (int32 c = 0; c < columnCount; ++c) {428if (size + sizeof(uint8) < totalSize) {429++size;430*buffer++ = (uint8)rows[r].values[c].size;431}432if (rows[r].values[c].size + size < totalSize) {433memcpy(buffer, rows[r].values[c].data, rows[r].values[c].size);434size += rows[r].values[c].size;435buffer += rows[r].values[c].size;436}437}438}439440if (size < totalSize)441memset(buffer, 0, totalSize - size);442}443void RSDK::SKU::UserDB::Clear()444{445sortedRowList.Clear();446loaded = false;447active = false;448valid = false;449uuid = 0;450rowCount = 0;451columnCount = 0;452memset(columnTypes, 0, sizeof(columnTypes));453memset(columnNames, 0, sizeof(columnNames));454memset(columnUUIDs, 0, sizeof(columnUUIDs));455memset(rows, 0, sizeof(rows));456rowsChanged = true;457}458459int32 RSDK::SKU::UserDB::GetColumnID(const char *name)460{461uint32 uuid = 0;462GenerateHashCRC(&uuid, (char *)name);463464int32 id = -1;465for (int32 i = 0; i < columnCount; ++i) {466if (uuid == columnUUIDs[i]) {467id = i;468break;469}470}471return id;472}473474int32 RSDK::SKU::UserDB::AddRow()475{476if (rowCount >= RETRO_USERDB_ROW_MAX)477return -1;478479UserDBRow *row = &rows[rowCount];480row->uuid = CreateRowUUID();481482time_t timeInfo;483time(&timeInfo);484tm *tmA = localtime(&timeInfo);485tm *tmB = localtime(&timeInfo);486487memcpy(&row->createTime, tmA, sizeof(tm));488memcpy(&row->changeTime, tmB, sizeof(tm));489490memset(row->values, 0, sizeof(UserDBValue) * RETRO_USERDB_COL_MAX);491++rowCount;492valid = true;493494Refresh();495rowsChanged = true;496return rowCount - 1;497}498bool32 RSDK::SKU::UserDB::RemoveRow(uint32 row)499{500if (row < rowCount) {501UserDBRow *entry = &rows[row];502memset(entry, 0, sizeof(UserDBRow));503504int32 id = (int32)(rowCount - row - 1);505memcpy(entry, &entry[1], id * sizeof(UserDBRow));506memset(&entry[id + 1], 0, sizeof(UserDBRow));507508--rowCount;509valid = true;510511Refresh();512rowsChanged = true;513}514return true;515}516bool32 RSDK::SKU::UserDB::RemoveAllRows()517{518rowCount = 0;519memset(rows, 0, sizeof(UserDBRow) * RETRO_USERDB_ROW_MAX);520Refresh();521return true;522}523uint16 RSDK::SKU::UserDB::GetRowByID(uint32 uuid)524{525if (!rowCount)526return -1;527528for (int32 i = 0; i < rowCount; ++i) {529if (uuid == rows[i].uuid) {530return i;531}532}533return -1;534}535536void RSDK::SKU::UserDB::FilterValues(UserDBValue *value, int32 column)537{538for (int32 i = sortedRowList.Count() - 1; i >= 0; --i) {539if (!value->CheckMatch(sortedRowIDs[i], column)) {540sortedRowList.Remove(i);541}542}543}544void RSDK::SKU::UserDB::AddSortFilter(const char *name, void *value)545{546int32 id = GetColumnID(name);547548if (id >= 0) {549if (sortedRowCount) {550UserDBValue dbValue;551// this is very hacky552dbValue.parent = (UserDBRow *)this;553dbValue.Set(columnTypes[id], value);554FilterValues(&dbValue, id);555SetupRowSortIDs();556}557}558}559560void RSDK::SKU::UserDB::SetupRowSortIDs()561{562sortedRowCount = 0;563memset(sortedRowIDs, 0, sizeof(sortedRowIDs));564565for (int32 i = 0; i < sortedRowList.Count(); ++i) {566sortedRowIDs[i] = *sortedRowList.At(i);567++sortedRowCount;568}569}570void RSDK::SKU::UserDB::RefreshSortList()571{572sortedRowList.Clear();573574for (int32 i = 0; i < rowCount; ++i) {575int32 *row = sortedRowList.Append();576if (row)577*row = i;578}579580rowsChanged = false;581582SetupRowSortIDs();583}584void RSDK::SKU::UserDB::SortRows(int32 type, char *name, bool32 sortAscending)585{586if (!rowsChanged && sortedRowCount) {587if (type || name) { // sort by value588int32 col = GetColumnID(name);589if (col >= 0) {590for (int32 i = 0; i < sortedRowList.Count(); i++) {591for (int32 j = i + 1; j < sortedRowList.Count(); j++) {592int32 *id1 = sortedRowList.At(i);593int32 *id2 = sortedRowList.At(j);594595if (rows[*id1].Compare(&rows[*id2], type, name, sortAscending)) {596int32 temp = *id1;597*id1 = *id2;598*id2 = temp;599}600}601}602603SetupRowSortIDs();604}605}606else { // sort by date607for (int32 i = 0; i < sortedRowList.Count(); i++) {608for (int32 j = i + 1; j < sortedRowList.Count(); j++) {609int32 *id1 = sortedRowList.At(i);610int32 *id2 = sortedRowList.At(j);611612double d = difftime(mktime(&rows[*id1].createTime), mktime(&rows[*id2].createTime));613614bool32 swap = false;615if (sortAscending)616swap = (d < 0) - (d > 0);617else618swap = (d > 0) - (d < 0);619620if (swap) {621int32 temp = *id1;622*id1 = *id2;623*id2 = temp;624}625}626}627628SetupRowSortIDs();629}630}631}632633uint32 RSDK::SKU::UserDB::CreateRowUUID()634{635bool32 flag = true;636uint32 uuid = 0;637638while (flag) {639uint8 bytes[4];640bytes[0] = rand();641bytes[1] = rand();642bytes[2] = rand();643bytes[3] = rand();644uuid = (bytes[0]) | (bytes[1] << 8) | (bytes[2] << 16) | (bytes[3] << 24);645646if (uuid < 0x10000000)647uuid |= 0x10000000;648649flag = false;650for (int32 e = 0; e < rowCount; ++e) {651if (uuid == rows[e].uuid) {652flag = true;653}654}655}656return uuid;657}658void RSDK::SKU::UserDB::Refresh()659{660parent = this;661for (int32 r = 0; r < RETRO_USERDB_ROW_MAX; ++r) {662rows[r].parent = this;663for (int32 c = 0; c < columnCount; ++c) {664rows[r].values[c].parent = &rows[r];665}666}667}668size_t RSDK::SKU::UserDB::GetSize()669{670int32 colSize = 1;671if (columnCount)672colSize = (0x10 * columnCount) + columnCount + 1;673674size_t size = colSize + 10;675676for (int32 r = 0; r < RETRO_USERDB_ROW_MAX; ++r) {677rows[r].parent = this;678int32 rowSize = (sizeof(tm) * 2) + sizeof(uint32);679for (int32 c = 0; c < columnCount; ++c) {680rowSize += sizeof(uint8) + rows[r].values[c].size;681}682size += rowSize;683}684685return size;686}687688// =======================689// USER DB STORAGE690// =======================691692RSDK::SKU::UserDBStorage::UserDBStorage()693{694unknown = 0;695696this->loadCallback[0] = UserDBStorage_LoadCB1;697this->loadCallback[1] = UserDBStorage_LoadCB2;698this->loadCallback[2] = UserDBStorage_LoadCB3;699this->loadCallback[3] = UserDBStorage_LoadCB4;700this->loadCallback[4] = UserDBStorage_LoadCB5;701this->loadCallback[5] = UserDBStorage_LoadCB6;702this->loadCallback[6] = UserDBStorage_LoadCB7;703this->loadCallback[7] = UserDBStorage_LoadCB8;704705this->saveCallback[0] = UserDBStorage_SaveCB1;706this->saveCallback[1] = UserDBStorage_SaveCB2;707this->saveCallback[2] = UserDBStorage_SaveCB3;708this->saveCallback[3] = UserDBStorage_SaveCB4;709this->saveCallback[4] = UserDBStorage_SaveCB5;710this->saveCallback[5] = UserDBStorage_SaveCB6;711this->saveCallback[6] = UserDBStorage_SaveCB7;712this->saveCallback[7] = UserDBStorage_SaveCB8;713}714715// UserDB Management716uint16 RSDK::SKU::UserDBStorage::InitUserDB(const char *name, va_list list)717{718int32 tableID = -1;719uint32 uuid = 0;720GenerateHashCRC(&uuid, (char *)name);721722for (int32 i = 0; i < RETRO_USERDB_MAX; ++i) {723if (!userDBStorage->userDB[i].loaded) {724tableID = i;725break;726}727}728729if (tableID == -1)730return -1;731732UserDB *userDB = &userDBStorage->userDB[tableID];733734userDB->loaded = true;735userDB->name = name;736GenerateHashCRC(&userDB->uuid, (char *)name);737userDB->Init(list);738userDB->parent->RefreshSortList();739740return tableID;741}742uint16 RSDK::SKU::UserDBStorage::LoadUserDB(const char *filename, void (*callback)(int32 status))743{744int32 tableID = -1;745uint32 uuid = 0;746GenerateHashCRC(&uuid, (char *)filename);747for (int32 i = 0; i < RETRO_USERDB_MAX; ++i) {748if (uuid == userDBStorage->userDB[i].uuid && userDBStorage->userDB[i].loaded)749return i;750}751752for (int32 i = 0; i < RETRO_USERDB_MAX; ++i) {753if (!userDBStorage->userDB[i].loaded) {754tableID = i;755break;756}757}758759if (tableID == -1) {760if (callback)761callback(STATUS_ERROR);762return -1;763}764765AllocateStorage((void **)&userDBStorage->readBuffer[tableID], sizeof(UserDB), DATASET_TMP, true);766userDBStorage->dbLoadCB[tableID] = UserDBStorage::LoadCB;767userDBStorage->callbacks[tableID] = callback;768TryLoadUserFile(filename, userDBStorage->readBuffer[tableID], sizeof(UserDB), userDBStorage->loadCallback[tableID]);769770UserDB *userDB = &userDBStorage->userDB[tableID];771userDB->loaded = true;772userDB->name = filename;773userDB->uuid = uuid;774775return tableID;776}777bool32 RSDK::SKU::UserDBStorage::SaveUserDB(uint16 tableID, void (*callback)(int32 status))778{779UserDB *userDB = &userDBStorage->userDB[tableID];780781bool32 success = false;782if (userDB->active) {783int32 totalSize = (int32)userDB->GetSize();784AllocateStorage((void **)&userDBStorage->writeBuffer[tableID], totalSize, DATASET_TMP, true);785userDB->Save(totalSize, (uint8 *)userDBStorage->writeBuffer[tableID]);786userDBStorage->dbSaveCB[tableID] = UserDBStorage::SaveCB;787userDBStorage->callbacks[tableID] = callback;788success = TrySaveUserFile(userDB->name, userDBStorage->writeBuffer[tableID], totalSize, userDBStorage->saveCallback[tableID], true);789}790else {791if (callback)792callback(STATUS_ERROR);793}794795return success;796}797void RSDK::SKU::UserDBStorage::ClearUserDB(uint16 tableID)798{799if (tableID == (uint16)-1)800return;801802UserDB *userDB = &userDBStorage->userDB[tableID];803if (userDB->loaded) {804userDB->Clear();805}806}807void RSDK::SKU::UserDBStorage::ClearAllUserDBs()808{809for (int32 i = 0; i < RETRO_USERDB_MAX; ++i) ClearUserDB(i);810}811812bool32 RSDK::SKU::UserDBStorage::LoadCB(uint16 tableID, int32 status)813{814bool32 succeeded = false;815if (status == STATUS_OK) {816UserDB *userDB = &userDBStorage->userDB[tableID];817818succeeded = userDB->Load((uint8 *)userDBStorage->readBuffer[tableID]);819if (succeeded) {820userDB->parent->RefreshSortList();821}822}823else {824RSDK::SKU::ClearUserDB(tableID);825}826RemoveStorageEntry((void **)&userDBStorage->readBuffer[tableID]);827828if (userDBStorage->callbacks[tableID]) {829userDBStorage->callbacks[tableID](succeeded ? status : STATUS_ERROR);830userDBStorage->callbacks[tableID] = NULL;831}832833return succeeded;834}835bool32 RSDK::SKU::UserDBStorage::SaveCB(uint16 tableID, int32 status)836{837RemoveStorageEntry((void **)&userDBStorage->writeBuffer[tableID]);838if (status != STATUS_OK)839userDBStorage->userDB[tableID].valid = false;840841if (userDBStorage->callbacks[tableID]) {842userDBStorage->callbacks[tableID](status);843userDBStorage->callbacks[tableID] = NULL;844return true;845}846return false;847}848849// =======================850// USER DB API851// =======================852853// UserDB Row Sorting854uint16 RSDK::SKU::SetupUserDBRowSorting(uint16 tableID)855{856if (tableID == (uint16)-1)857return 0;858userDBStorage->userDB[tableID].parent->RefreshSortList();859860return userDBStorage->userDB[tableID].sortedRowCount;861}862int32 RSDK::SKU::AddUserDBRowSortFilter(uint16 tableID, int32 type, const char *name, void *value)863{864if (tableID == (uint16)-1)865return 0;866UserDB *userDB = &userDBStorage->userDB[tableID];867if (!userDB->active)868return 0;869870userDB->parent->AddSortFilter(name, value);871return userDB->sortedRowCount;872}873int32 RSDK::SKU::SortUserDBRows(uint16 tableID, int32 type, const char *name, bool32 sortAscending)874{875if (tableID == (uint16)-1)876return 0;877878UserDB *userDB = &userDBStorage->userDB[tableID];879if (!userDB->active)880return 0;881882userDB->parent->SortRows(type, (char *)name, sortAscending);883return userDB->sortedRowCount;884}885int32 RSDK::SKU::GetSortedUserDBRowCount(uint16 tableID)886{887if (tableID == (uint16)-1)888return 0;889890UserDB *userDB = &userDBStorage->userDB[tableID];891if (!userDB->active)892return 0;893894return userDB->sortedRowCount;895}896int32 RSDK::SKU::GetSortedUserDBRowID(uint16 tableID, uint16 sortedRowID)897{898if (tableID == (uint16)-1)899return -1;900901UserDB *userDB = &userDBStorage->userDB[tableID];902if (!userDB->active || userDB->rowsChanged || sortedRowID >= userDB->sortedRowCount)903return -1;904905return userDB->sortedRowIDs[sortedRowID];906}907908// UserDB Values909bool32 RSDK::SKU::GetUserDBValue(uint16 tableID, uint32 rowID, int32 type, char *name, void *value)910{911if (tableID == (uint16)-1 || rowID == (uint16)-1 || !userDBStorage->userDB[tableID].active)912return false;913return userDBStorage->userDB[tableID].rows[rowID].GetValue(type, name, value);914}915bool32 RSDK::SKU::SetUserDBValue(uint16 tableID, uint32 rowID, int32 type, char *name, void *value)916{917if (tableID == (uint16)-1 || rowID == (uint16)-1 || !userDBStorage->userDB[tableID].active)918return false;919920return userDBStorage->userDB[tableID].rows[rowID].AddValue(type, name, value);921}922923// UserDB Misc924bool32 RSDK::SKU::GetUserDBRowsChanged(uint16 tableID) { return userDBStorage->userDB[tableID].rowsChanged; }925void RSDK::SKU::GetUserDBRowCreationTime(uint16 tableID, uint16 rowID, char *buf, size_t size, char *format)926{927if (tableID != (uint16)-1 && rowID != (uint16)-1) {928UserDB *userDB = &userDBStorage->userDB[tableID];929if (userDB->active)930strftime(buf, size, format, &userDB->rows[rowID].createTime);931}932}933934// =======================935// USER DB CALLBACKS936// =======================937938void RSDK::SKU::UserDBStorage_LoadCB1(int32 status)939{940if (userDBStorage->dbLoadCB[0])941userDBStorage->dbLoadCB[0](0, status);942}943void RSDK::SKU::UserDBStorage_LoadCB2(int32 status)944{945if (userDBStorage->dbLoadCB[1])946userDBStorage->dbLoadCB[1](1, status);947}948void RSDK::SKU::UserDBStorage_LoadCB3(int32 status)949{950if (userDBStorage->dbLoadCB[2])951userDBStorage->dbLoadCB[2](2, status);952}953void RSDK::SKU::UserDBStorage_LoadCB4(int32 status)954{955if (userDBStorage->dbLoadCB[3])956userDBStorage->dbLoadCB[3](3, status);957}958void RSDK::SKU::UserDBStorage_LoadCB5(int32 status)959{960if (userDBStorage->dbLoadCB[4])961userDBStorage->dbLoadCB[4](4, status);962}963void RSDK::SKU::UserDBStorage_LoadCB6(int32 status)964{965if (userDBStorage->dbLoadCB[5])966userDBStorage->dbLoadCB[5](5, status);967}968void RSDK::SKU::UserDBStorage_LoadCB7(int32 status)969{970if (userDBStorage->dbLoadCB[6])971userDBStorage->dbLoadCB[6](6, status);972}973void RSDK::SKU::UserDBStorage_LoadCB8(int32 status)974{975if (userDBStorage->dbLoadCB[7])976userDBStorage->dbLoadCB[7](7, status);977}978979void RSDK::SKU::UserDBStorage_SaveCB1(int32 status)980{981if (userDBStorage->dbSaveCB[0])982userDBStorage->dbSaveCB[0](0, status);983}984void RSDK::SKU::UserDBStorage_SaveCB2(int32 status)985{986if (userDBStorage->dbSaveCB[1])987userDBStorage->dbSaveCB[1](1, status);988}989void RSDK::SKU::UserDBStorage_SaveCB3(int32 status)990{991if (userDBStorage->dbSaveCB[2])992userDBStorage->dbSaveCB[2](2, status);993}994void RSDK::SKU::UserDBStorage_SaveCB4(int32 status)995{996if (userDBStorage->dbSaveCB[3])997userDBStorage->dbSaveCB[3](3, status);998}999void RSDK::SKU::UserDBStorage_SaveCB5(int32 status)1000{1001if (userDBStorage->dbSaveCB[4])1002userDBStorage->dbSaveCB[4](4, status);1003}1004void RSDK::SKU::UserDBStorage_SaveCB6(int32 status)1005{1006if (userDBStorage->dbSaveCB[5])1007userDBStorage->dbSaveCB[5](5, status);1008}1009void RSDK::SKU::UserDBStorage_SaveCB7(int32 status)1010{1011if (userDBStorage->dbSaveCB[6])1012userDBStorage->dbSaveCB[6](6, status);1013}1014void RSDK::SKU::UserDBStorage_SaveCB8(int32 status)1015{1016if (userDBStorage->dbSaveCB[7])1017userDBStorage->dbSaveCB[7](7, status);1018}10191020#endif10211022void (*RSDK::SKU::preLoadSaveFileCB)();1023void (*RSDK::SKU::postLoadSaveFileCB)();1024char RSDK::SKU::userFileDir[0x100];10251026bool32 RSDK::SKU::LoadUserFile(const char *filename, void *buffer, uint32 bufSize)1027{1028if (preLoadSaveFileCB)1029preLoadSaveFileCB();10301031char fullFilePath[0x400];1032#if RETRO_USE_MOD_LOADER1033if (strlen(customUserFileDir))1034sprintf_s(fullFilePath, sizeof(fullFilePath), "%s%s", customUserFileDir, filename);1035else1036sprintf_s(fullFilePath, sizeof(fullFilePath), "%s%s", userFileDir, filename);1037#else1038sprintf_s(fullFilePath, sizeof(fullFilePath), "%s%s", userFileDir, filename);1039#endif1040PrintLog(PRINT_NORMAL, "Attempting to load user file: %s", fullFilePath);10411042FileIO *file = fOpen(fullFilePath, "rb");1043if (file) {1044fSeek(file, 0, SEEK_END);1045uint32 fSize = (uint32)fTell(file);1046fSeek(file, 0, SEEK_SET);1047uint32 size = bufSize;1048if (bufSize > fSize)1049size = fSize;1050fRead(buffer, 1, size, file);1051fClose(file);10521053if (postLoadSaveFileCB)1054postLoadSaveFileCB();10551056return true;1057}1058else {1059if (postLoadSaveFileCB)1060postLoadSaveFileCB();10611062PrintLog(PRINT_NORMAL, "Nope!");1063}10641065return false;1066}1067bool32 RSDK::SKU::SaveUserFile(const char *filename, void *buffer, uint32 bufSize)1068{1069if (preLoadSaveFileCB)1070preLoadSaveFileCB();10711072char fullFilePath[0x400];1073#if RETRO_USE_MOD_LOADER1074if (strlen(customUserFileDir))1075sprintf_s(fullFilePath, sizeof(fullFilePath), "%s%s", customUserFileDir, filename);1076else1077sprintf_s(fullFilePath, sizeof(fullFilePath), "%s%s", userFileDir, filename);1078#else1079sprintf_s(fullFilePath, sizeof(fullFilePath), "%s%s", userFileDir, filename);1080#endif1081PrintLog(PRINT_NORMAL, "Attempting to save user file: %s", fullFilePath);10821083FileIO *file = fOpen(fullFilePath, "wb");1084if (file) {1085fWrite(buffer, 1, bufSize, file);1086fClose(file);10871088if (postLoadSaveFileCB)1089postLoadSaveFileCB();10901091return true;1092}1093else {1094if (postLoadSaveFileCB)1095postLoadSaveFileCB();10961097PrintLog(PRINT_NORMAL, "Nope!");1098}1099return false;1100}1101bool32 RSDK::SKU::DeleteUserFile(const char *filename)1102{1103if (preLoadSaveFileCB)1104preLoadSaveFileCB();11051106char fullFilePath[0x400];1107#if RETRO_USE_MOD_LOADER1108if (strlen(customUserFileDir))1109sprintf_s(fullFilePath, sizeof(fullFilePath), "%s%s", customUserFileDir, filename);1110else1111sprintf_s(fullFilePath, sizeof(fullFilePath), "%s%s", userFileDir, filename);1112#else1113sprintf_s(fullFilePath, sizeof(fullFilePath), "%s%s", userFileDir, filename);1114#endif1115PrintLog(PRINT_NORMAL, "Attempting to delete user file: %s", fullFilePath);1116int32 status = remove(fullFilePath);11171118if (postLoadSaveFileCB)1119postLoadSaveFileCB();11201121return status == 0;1122}11231124#if !RETRO_REV021125bool32 RSDK::SKU::TryLoadUserFile(const char *filename, void *buffer, uint32 size, void (*callback)(int32 status))1126{1127bool32 success = false;11281129success = LoadUserFile(filename, buffer, size);11301131if (callback)1132callback(success ? STATUS_OK : STATUS_ERROR);11331134return success;1135}1136bool32 RSDK::SKU::TrySaveUserFile(const char *filename, void *buffer, uint32 size, void (*callback)(int32 status))1137{1138bool32 success = false;11391140success = SaveUserFile(filename, buffer, size);11411142if (callback)1143callback(success ? STATUS_OK : STATUS_ERROR);11441145return success;1146}1147#endif11481149void RSDK::SKU::InitUserDirectory()1150{1151#if RETRO_PLATFORM == RETRO_OSX11521153char buffer[0x100];1154sprintf_s(buffer, sizeof(buffer), "%s/RSDKv5/", getResourcesPath());1155SKU::SetUserFileCallbacks(buffer, NULL, NULL);11561157#elif RETRO_PLATFORM == RETRO_ANDROID11581159// done by javaside11601161#elif RETRO_PLATFORM == RETRO_LINUX11621163SKU::SetUserFileCallbacks("./", NULL, NULL);11641165#else11661167SKU::SetUserFileCallbacks("", NULL, NULL);11681169#endif1170}11711172