mirror of
https://github.com/jpd002/Play-.git
synced 2025-04-28 21:57:57 +03:00
267 lines
8.6 KiB
C++
267 lines
8.6 KiB
C++
#include <cassert>
|
|
#include "../AppConfig.h"
|
|
#include "string_format.h"
|
|
#include "PathUtils.h"
|
|
#include "BootablesDbClient.h"
|
|
#include "sqlite/SqliteStatement.h"
|
|
|
|
using namespace BootablesDb;
|
|
|
|
#define DATABASE_VERSION 3
|
|
|
|
static const char* g_dbFileName = "bootables.db";
|
|
|
|
static const char* g_bootablesTableCreateStatement =
|
|
"CREATE TABLE IF NOT EXISTS bootables"
|
|
"("
|
|
" path TEXT PRIMARY KEY,"
|
|
" discId VARCHAR(10) DEFAULT '',"
|
|
" title TEXT DEFAULT '',"
|
|
" coverUrl TEXT DEFAULT '',"
|
|
" lastBootedTime INTEGER DEFAULT 0,"
|
|
" overview TEXT DEFAULT '',"
|
|
" bootableType INTEGER DEFAULT 0"
|
|
")";
|
|
|
|
CClient::CClient()
|
|
{
|
|
m_dbPath = CAppConfig::GetInstance().GetBasePath() / g_dbFileName;
|
|
|
|
UpgradeDb();
|
|
|
|
m_db = Framework::CSqliteDb(Framework::PathUtils::GetNativeStringFromPath(m_dbPath).c_str(),
|
|
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
|
|
|
|
{
|
|
auto query = string_format("PRAGMA user_version = %d", DATABASE_VERSION);
|
|
Framework::CSqliteStatement statement(m_db, query.c_str());
|
|
statement.StepNoResult();
|
|
}
|
|
|
|
{
|
|
Framework::CSqliteStatement statement(m_db, g_bootablesTableCreateStatement);
|
|
statement.StepNoResult();
|
|
}
|
|
|
|
{
|
|
auto path = Framework::PathUtils::GetAppResourcesPath() / "states.db";
|
|
std::error_code errorCode;
|
|
if(fs::exists(path, errorCode))
|
|
{
|
|
char* err = NULL;
|
|
auto query = string_format("ATTACH DATABASE '%s' as 'stateDB';", path.string().c_str());
|
|
sqlite3_exec(m_db, query.c_str(), 0, 0, &err);
|
|
m_attachedState = err == NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CClient::BootableExists(const fs::path& path)
|
|
{
|
|
Framework::CSqliteStatement statement(m_db, "SELECT * FROM bootables WHERE path = ?");
|
|
statement.BindText(1, Framework::PathUtils::GetNativeStringFromPath(path).c_str());
|
|
return statement.Step();
|
|
}
|
|
|
|
Bootable CClient::GetBootable(const fs::path& path)
|
|
{
|
|
Framework::CSqliteStatement statement(m_db, "SELECT * FROM bootables WHERE path = ?");
|
|
statement.BindText(1, Framework::PathUtils::GetNativeStringFromPath(path).c_str());
|
|
statement.StepWithResult();
|
|
return ReadBootable(statement);
|
|
}
|
|
|
|
std::vector<Bootable> CClient::GetBootables(int32_t sortMethod)
|
|
{
|
|
std::string query = "SELECT * FROM bootables ";
|
|
|
|
switch(sortMethod)
|
|
{
|
|
case SORT_METHOD_RECENT:
|
|
query += "WHERE lastBootedTime != 0 Order By lastBootedTime DESC ";
|
|
break;
|
|
case SORT_METHOD_HOMEBREW:
|
|
query += "WHERE path LIKE '%.elf' COLLATE NOCASE ";
|
|
break;
|
|
case SORT_METHOD_ARCADE:
|
|
query += "WHERE path LIKE '%.arcadedef' COLLATE NOCASE ORDER BY title";
|
|
break;
|
|
case SORT_METHOD_NONE:
|
|
break;
|
|
}
|
|
std::vector<Bootable> bootables;
|
|
|
|
Framework::CSqliteStatement statement(m_db, query.c_str());
|
|
while(statement.Step())
|
|
{
|
|
auto bootable = ReadBootable(statement);
|
|
bootables.push_back(bootable);
|
|
}
|
|
|
|
return bootables;
|
|
}
|
|
|
|
void CClient::RegisterBootable(const fs::path& path, const char* title, const char* discId, BootableUtils::BOOTABLE_TYPE bootableType)
|
|
{
|
|
Framework::CSqliteStatement statement(m_db, "INSERT OR IGNORE INTO bootables (path, title, discId, bootableType) VALUES (?,?,?,?)");
|
|
statement.BindText(1, Framework::PathUtils::GetNativeStringFromPath(path).c_str());
|
|
statement.BindText(2, title, true);
|
|
statement.BindText(3, discId, true);
|
|
statement.BindInteger(4, bootableType);
|
|
statement.StepNoResult();
|
|
}
|
|
|
|
void CClient::UnregisterBootable(const fs::path& path)
|
|
{
|
|
Framework::CSqliteStatement statement(m_db, "DELETE FROM bootables WHERE path = ?");
|
|
statement.BindText(1, Framework::PathUtils::GetNativeStringFromPath(path).c_str());
|
|
statement.StepNoResult();
|
|
}
|
|
|
|
void CClient::SetDiscId(const fs::path& path, const char* discId)
|
|
{
|
|
Framework::CSqliteStatement statement(m_db, "UPDATE bootables SET discId = ? WHERE path = ?");
|
|
statement.BindText(1, discId, true);
|
|
statement.BindText(2, Framework::PathUtils::GetNativeStringFromPath(path).c_str());
|
|
statement.StepNoResult();
|
|
}
|
|
|
|
void CClient::SetTitle(const fs::path& path, const char* title)
|
|
{
|
|
Framework::CSqliteStatement statement(m_db, "UPDATE bootables SET title = ? WHERE path = ?");
|
|
statement.BindText(1, title, true);
|
|
statement.BindText(2, Framework::PathUtils::GetNativeStringFromPath(path).c_str());
|
|
statement.StepNoResult();
|
|
}
|
|
|
|
void CClient::SetCoverUrl(const fs::path& path, const char* coverUrl)
|
|
{
|
|
Framework::CSqliteStatement statement(m_db, "UPDATE bootables SET coverUrl = ? WHERE path = ?");
|
|
statement.BindText(1, coverUrl, true);
|
|
statement.BindText(2, Framework::PathUtils::GetNativeStringFromPath(path).c_str());
|
|
statement.StepNoResult();
|
|
}
|
|
|
|
void CClient::SetLastBootedTime(const fs::path& path, time_t lastBootedTime)
|
|
{
|
|
Framework::CSqliteStatement statement(m_db, "UPDATE bootables SET lastBootedTime = ? WHERE path = ?");
|
|
statement.BindInteger(1, lastBootedTime);
|
|
statement.BindText(2, Framework::PathUtils::GetNativeStringFromPath(path).c_str());
|
|
statement.StepNoResult();
|
|
}
|
|
|
|
void CClient::SetOverview(const fs::path& path, const char* overview)
|
|
{
|
|
Framework::CSqliteStatement statement(m_db, "UPDATE bootables SET overview = ? WHERE path = ?");
|
|
statement.BindText(1, overview, true);
|
|
statement.BindText(2, Framework::PathUtils::GetNativeStringFromPath(path).c_str());
|
|
statement.StepNoResult();
|
|
}
|
|
|
|
BootableStateList CClient::GetGameStates(std::string discId)
|
|
{
|
|
BootableStateList states;
|
|
if(!m_attachedState)
|
|
return states;
|
|
|
|
std::string query = "SELECT stateDB.labels.name AS stateName, stateDB.labels.color AS stateColor FROM stateDB.games ";
|
|
query += "LEFT JOIN stateDB.labels ON stateDB.games.state = stateDB.labels.name ";
|
|
query += "WHERE stateDB.games.discId = ?;";
|
|
|
|
Framework::CSqliteStatement statement(m_db, query.c_str());
|
|
statement.BindText(1, discId.c_str(), true);
|
|
while(statement.Step())
|
|
{
|
|
BootableState state;
|
|
state.name = reinterpret_cast<const char*>(sqlite3_column_text(statement, 0));
|
|
state.color = reinterpret_cast<const char*>(sqlite3_column_text(statement, 1));
|
|
states.push_back(state);
|
|
}
|
|
return states;
|
|
}
|
|
|
|
BootableStateList CClient::GetStates()
|
|
{
|
|
BootableStateList states;
|
|
if(!m_attachedState)
|
|
return states;
|
|
|
|
std::string query = "SELECT stateDB.labels.name AS stateName, stateDB.labels.color AS stateColor FROM stateDB.labels;";
|
|
|
|
Framework::CSqliteStatement statement(m_db, query.c_str());
|
|
while(statement.Step())
|
|
{
|
|
BootableState state;
|
|
state.name = reinterpret_cast<const char*>(sqlite3_column_text(statement, 0));
|
|
state.color = reinterpret_cast<const char*>(sqlite3_column_text(statement, 1));
|
|
states.push_back(state);
|
|
}
|
|
return states;
|
|
}
|
|
|
|
Bootable CClient::ReadBootable(Framework::CSqliteStatement& statement)
|
|
{
|
|
Bootable bootable;
|
|
bootable.path = Framework::PathUtils::GetPathFromNativeString(reinterpret_cast<const char*>(sqlite3_column_text(statement, 0)));
|
|
bootable.discId = reinterpret_cast<const char*>(sqlite3_column_text(statement, 1));
|
|
bootable.title = reinterpret_cast<const char*>(sqlite3_column_text(statement, 2));
|
|
bootable.coverUrl = reinterpret_cast<const char*>(sqlite3_column_text(statement, 3));
|
|
bootable.overview = reinterpret_cast<const char*>(sqlite3_column_text(statement, 5));
|
|
bootable.lastBootedTime = sqlite3_column_int(statement, 4);
|
|
bootable.states = GetGameStates(bootable.discId);
|
|
bootable.bootableType = static_cast<BootableUtils::BOOTABLE_TYPE>(sqlite3_column_int(statement, 6));
|
|
return bootable;
|
|
}
|
|
|
|
void CClient::UpgradeDb()
|
|
{
|
|
try
|
|
{
|
|
auto db = Framework::CSqliteDb(Framework::PathUtils::GetNativeStringFromPath(m_dbPath).c_str(), SQLITE_OPEN_READWRITE);
|
|
|
|
Framework::CSqliteStatement statement(db, "PRAGMA user_version");
|
|
statement.StepWithResult();
|
|
|
|
auto currentVersion = sqlite3_column_int(statement, 0);
|
|
while(currentVersion < DATABASE_VERSION)
|
|
{
|
|
switch(currentVersion)
|
|
{
|
|
case 2:
|
|
{
|
|
Framework::CSqliteStatement statement(db, "ALTER TABLE bootables ADD COLUMN bootableType INTEGER DEFAULT 0");
|
|
statement.StepNoResult();
|
|
|
|
{
|
|
Framework::CSqliteStatement statement(db, "UPDATE bootables SET bootableType = ? WHERE path LIKE '%.arcade%';");
|
|
statement.BindInteger(1, BootableUtils::PS2_ARCADE);
|
|
statement.StepNoResult();
|
|
}
|
|
{
|
|
Framework::CSqliteStatement statement(db, "UPDATE bootables SET bootableType = ? WHERE path LIKE '%.elf%';");
|
|
statement.BindInteger(1, BootableUtils::PS2_ELF);
|
|
statement.StepNoResult();
|
|
}
|
|
{
|
|
Framework::CSqliteStatement statement(db, "UPDATE bootables SET bootableType = ? WHERE bootableType = 0;");
|
|
statement.BindInteger(1, BootableUtils::PS2_DISC);
|
|
statement.StepNoResult();
|
|
}
|
|
|
|
currentVersion = 3;
|
|
}
|
|
break;
|
|
default:
|
|
fs::remove(m_dbPath);
|
|
return;
|
|
}
|
|
}
|
|
auto query = string_format("PRAGMA user_version = %d", currentVersion);
|
|
Framework::CSqliteStatement versionStatement(db, query.c_str());
|
|
versionStatement.StepNoResult();
|
|
}
|
|
catch(...)
|
|
{
|
|
fs::remove(m_dbPath);
|
|
}
|
|
}
|