Library: store platform models in database, render GBC/SGB icons

This commit is contained in:
Adam Higerd 2022-07-02 14:10:48 -05:00
parent ba8671d1d6
commit 447054674d
8 changed files with 94 additions and 5 deletions

View File

@ -15,6 +15,8 @@ CXX_GUARD_START
#include <mgba/core/core.h> #include <mgba/core/core.h>
#include <mgba-util/vector.h> #include <mgba-util/vector.h>
#define M_LIBRARY_MODEL_UNKNOWN -1
struct mLibraryEntry { struct mLibraryEntry {
const char* base; const char* base;
const char* filename; const char* filename;
@ -26,6 +28,7 @@ struct mLibraryEntry {
uint32_t crc32; uint32_t crc32;
uint8_t md5[16]; uint8_t md5[16];
uint8_t sha1[20]; uint8_t sha1[20];
int platformModels;
}; };
#ifdef USE_SQLITE3 #ifdef USE_SQLITE3

View File

@ -9,6 +9,11 @@
#include <mgba-util/string.h> #include <mgba-util/string.h>
#include <mgba-util/vfs.h> #include <mgba-util/vfs.h>
#ifdef M_CORE_GB
#include <mgba/gb/interface.h>
#include <mgba/internal/gb/gb.h>
#endif
#ifdef USE_SQLITE3 #ifdef USE_SQLITE3
#include <sqlite3.h> #include <sqlite3.h>
@ -108,12 +113,38 @@ static void _bindConstraints(sqlite3_stmt* statement, const struct mLibraryEntry
sqlite3_bind_int(statement, useIndex, 1); sqlite3_bind_int(statement, useIndex, 1);
sqlite3_bind_int(statement, index, constraints->platform); sqlite3_bind_int(statement, index, constraints->platform);
} }
if (constraints->platformModels != M_LIBRARY_MODEL_UNKNOWN) {
index = sqlite3_bind_parameter_index(statement, ":models");
sqlite3_bind_int(statement, index, constraints->platformModels);
}
} }
struct mLibrary* mLibraryCreateEmpty(void) { struct mLibrary* mLibraryCreateEmpty(void) {
return mLibraryLoad(":memory:"); return mLibraryLoad(":memory:");
} }
static int _mLibraryTableVersion(struct mLibrary* library, const char* tableName) {
int version = -1;
static const char getVersion[] = "SELECT version FROM version WHERE tname=?";
sqlite3_stmt* getVersionStmt;
if (sqlite3_prepare_v2(library->db, getVersion, -1, &getVersionStmt, NULL)) {
goto error;
}
sqlite3_clear_bindings(getVersionStmt);
sqlite3_reset(getVersionStmt);
sqlite3_bind_text(getVersionStmt, 1, tableName, -1, SQLITE_TRANSIENT);
if (sqlite3_step(getVersionStmt) != SQLITE_DONE) {
version = sqlite3_column_int(getVersionStmt, 0);
}
error:
sqlite3_finalize(getVersionStmt);
return version;
}
struct mLibrary* mLibraryLoad(const char* path) { struct mLibrary* mLibraryLoad(const char* path) {
struct mLibrary* library = malloc(sizeof(*library)); struct mLibrary* library = malloc(sizeof(*library));
memset(library, 0, sizeof(*library)); memset(library, 0, sizeof(*library));
@ -140,6 +171,7 @@ struct mLibrary* mLibraryLoad(const char* path) {
"\n internalTitle TEXT," "\n internalTitle TEXT,"
"\n internalCode TEXT," "\n internalCode TEXT,"
"\n platform INTEGER NOT NULL DEFAULT -1," "\n platform INTEGER NOT NULL DEFAULT -1,"
"\n models INTEGER NULL,"
"\n size INTEGER," "\n size INTEGER,"
"\n crc32 INTEGER," "\n crc32 INTEGER,"
"\n md5 BLOB," "\n md5 BLOB,"
@ -159,18 +191,35 @@ struct mLibrary* mLibraryLoad(const char* path) {
"\n CREATE INDEX IF NOT EXISTS sha1 ON roms (sha1);" "\n CREATE INDEX IF NOT EXISTS sha1 ON roms (sha1);"
"\n INSERT OR IGNORE INTO version (tname, version) VALUES ('version', 1);" "\n INSERT OR IGNORE INTO version (tname, version) VALUES ('version', 1);"
"\n INSERT OR IGNORE INTO version (tname, version) VALUES ('roots', 1);" "\n INSERT OR IGNORE INTO version (tname, version) VALUES ('roots', 1);"
"\n INSERT OR IGNORE INTO version (tname, version) VALUES ('roms', 1);" "\n INSERT OR IGNORE INTO version (tname, version) VALUES ('roms', 2);"
"\n INSERT OR IGNORE INTO version (tname, version) VALUES ('paths', 1);"; "\n INSERT OR IGNORE INTO version (tname, version) VALUES ('paths', 1);";
if (sqlite3_exec(library->db, createTables, NULL, NULL, NULL)) { if (sqlite3_exec(library->db, createTables, NULL, NULL, NULL)) {
goto error; goto error;
} }
int romsTableVersion = _mLibraryTableVersion(library, "roms");
if (romsTableVersion < 0) {
goto error;
} else if (romsTableVersion < 2) {
static const char upgradeRomsTable[] =
" ALTER TABLE roms"
"\nADD COLUMN models INTEGER NULL";
if (sqlite3_exec(library->db, upgradeRomsTable, NULL, NULL, NULL)) {
goto error;
}
static const char updateRomsTableVersion[] = "UPDATE version SET version=2 WHERE tname='roms'";
if (sqlite3_exec(library->db, updateRomsTableVersion, NULL, NULL, NULL)) {
goto error;
}
}
static const char insertPath[] = "INSERT INTO paths (romid, path, customTitle, rootid) VALUES (?, ?, ?, ?);"; static const char insertPath[] = "INSERT INTO paths (romid, path, customTitle, rootid) VALUES (?, ?, ?, ?);";
if (sqlite3_prepare_v2(library->db, insertPath, -1, &library->insertPath, NULL)) { if (sqlite3_prepare_v2(library->db, insertPath, -1, &library->insertPath, NULL)) {
goto error; goto error;
} }
static const char insertRom[] = "INSERT INTO roms (crc32, md5, sha1, size, internalCode, platform) VALUES (:crc32, :md5, :sha1, :size, :internalCode, :platform);"; static const char insertRom[] = "INSERT INTO roms (crc32, md5, sha1, size, internalCode, platform, :models) VALUES (:crc32, :md5, :sha1, :size, :internalCode, :platform, :models);";
if (sqlite3_prepare_v2(library->db, insertRom, -1, &library->insertRom, NULL)) { if (sqlite3_prepare_v2(library->db, insertRom, -1, &library->insertRom, NULL)) {
goto error; goto error;
} }
@ -318,6 +367,15 @@ bool _mLibraryAddEntry(struct mLibrary* library, const char* filename, const cha
core->checksum(core, &entry.md5, mCHECKSUM_MD5); core->checksum(core, &entry.md5, mCHECKSUM_MD5);
core->checksum(core, &entry.sha1, mCHECKSUM_SHA1); core->checksum(core, &entry.sha1, mCHECKSUM_SHA1);
entry.platform = core->platform(core); entry.platform = core->platform(core);
entry.platformModels = M_LIBRARY_MODEL_UNKNOWN;
#ifdef M_CORE_GB
if (entry.platform == mPLATFORM_GB) {
struct GB* gb = (struct GB*) core->board;
if (gb->memory.rom) {
entry.platformModels = GBValidModels(gb->memory.rom);
}
}
#endif
entry.title = NULL; entry.title = NULL;
entry.base = base; entry.base = base;
entry.filename = filename; entry.filename = filename;
@ -448,6 +506,8 @@ size_t mLibraryGetEntries(struct mLibrary* library, struct mLibraryListing* out,
} }
} else if (strcmp(colName, "platform") == 0) { } else if (strcmp(colName, "platform") == 0) {
entry->platform = sqlite3_column_int(library->select, i); entry->platform = sqlite3_column_int(library->select, i);
} else if (strcmp(colName, "models") == 0) {
entry->platformModels = sqlite3_column_int(library->select, i);
} else if (strcmp(colName, "size") == 0) { } else if (strcmp(colName, "size") == 0) {
entry->filesize = sqlite3_column_int64(library->select, i); entry->filesize = sqlite3_column_int64(library->select, i);
} else if (strcmp(colName, "internalCode") == 0 && sqlite3_column_type(library->select, i) == SQLITE_TEXT) { } else if (strcmp(colName, "internalCode") == 0 && sqlite3_column_type(library->select, i) == SQLITE_TEXT) {

View File

@ -6,6 +6,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "LibraryEntry.h" #include "LibraryEntry.h"
#include "utils.h"
#include <mgba/core/library.h> #include <mgba/core/library.h>
using namespace QGBA; using namespace QGBA;
@ -22,6 +24,7 @@ LibraryEntry::LibraryEntry(const mLibraryEntry* entry)
, internalTitle(entry->internalTitle) , internalTitle(entry->internalTitle)
, internalCode(entry->internalCode) , internalCode(entry->internalCode)
, platform(entry->platform) , platform(entry->platform)
, platformModels(entry->platformModels)
, filesize(entry->filesize) , filesize(entry->filesize)
, crc32(entry->crc32) , crc32(entry->crc32)
{ {
@ -38,6 +41,10 @@ QString LibraryEntry::displayTitle(bool showFilename) const {
return title; return title;
} }
QString LibraryEntry::displayPlatform() const {
return nicePlatformFormat(platform, platformModels);
}
bool LibraryEntry::operator==(const LibraryEntry& other) const { bool LibraryEntry::operator==(const LibraryEntry& other) const {
return other.fullpath == fullpath; return other.fullpath == fullpath;
} }

View File

@ -25,6 +25,7 @@ struct LibraryEntry {
bool isNull() const; bool isNull() const;
QString displayTitle(bool showFilename = false) const; QString displayTitle(bool showFilename = false) const;
QString displayPlatform() const;
QString base; QString base;
QString filename; QString filename;
@ -33,6 +34,7 @@ struct LibraryEntry {
QByteArray internalTitle; QByteArray internalTitle;
QByteArray internalCode; QByteArray internalCode;
mPlatform platform; mPlatform platform;
int platformModels;
size_t filesize; size_t filesize;
uint32_t crc32; uint32_t crc32;

View File

@ -21,6 +21,7 @@ static const QStringList iconSets{
"GBA", "GBA",
"GBC", "GBC",
"GB", "GB",
"SGB",
// "DS", // "DS",
}; };
@ -348,7 +349,7 @@ QVariant LibraryModel::data(const QModelIndex& index, int role) const {
switch (index.column()) { switch (index.column()) {
case COL_NAME: case COL_NAME:
if (role == Qt::DecorationRole) { if (role == Qt::DecorationRole) {
return m_icons.value(nicePlatformFormat(entry->platform), qApp->style()->standardIcon(QStyle::SP_FileIcon)); return m_icons.value(entry->displayPlatform(), qApp->style()->standardIcon(QStyle::SP_FileIcon));
} }
return entry->displayTitle(m_showFilename); return entry->displayTitle(m_showFilename);
case COL_LOCATION: case COL_LOCATION:

View File

@ -19,6 +19,12 @@
<file>../../../res/gbc-icon-24.png</file> <file>../../../res/gbc-icon-24.png</file>
<file>../../../res/gbc-icon-16.png</file> <file>../../../res/gbc-icon-16.png</file>
<file>../../../res/gbc-icon.svg</file> <file>../../../res/gbc-icon.svg</file>
<file>../../../res/sgb-icon-256.png</file>
<file>../../../res/sgb-icon-128.png</file>
<file>../../../res/sgb-icon-32.png</file>
<file>../../../res/sgb-icon-24.png</file>
<file>../../../res/sgb-icon-16.png</file>
<file>../../../res/sgb-icon.svg</file>
<file>../../../res/gba-icon-256.png</file> <file>../../../res/gba-icon-256.png</file>
<file>../../../res/gba-icon-128.png</file> <file>../../../res/gba-icon-128.png</file>
<file>../../../res/gba-icon-32.png</file> <file>../../../res/gba-icon-32.png</file>

View File

@ -5,6 +5,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "utils.h" #include "utils.h"
#include <mgba/core/library.h>
#include <mgba/gb/interface.h>
#include <QCoreApplication> #include <QCoreApplication>
#include <QHostAddress> #include <QHostAddress>
#include <QKeySequence> #include <QKeySequence>
@ -30,7 +33,7 @@ QString niceSizeFormat(size_t filesize) {
return unit.arg(size, 0, 'f', int(size * 10) % 10 ? 1 : 0); return unit.arg(size, 0, 'f', int(size * 10) % 10 ? 1 : 0);
} }
QString nicePlatformFormat(mPlatform platform) { QString nicePlatformFormat(mPlatform platform, int validModels) {
switch (platform) { switch (platform) {
#ifdef M_CORE_GBA #ifdef M_CORE_GBA
case mPLATFORM_GBA: case mPLATFORM_GBA:
@ -38,6 +41,13 @@ QString nicePlatformFormat(mPlatform platform) {
#endif #endif
#ifdef M_CORE_GB #ifdef M_CORE_GB
case mPLATFORM_GB: case mPLATFORM_GB:
if (validModels != M_LIBRARY_MODEL_UNKNOWN) {
if (validModels & GB_MODEL_CGB) {
return QObject::tr("GBC");
} else if (validModels & GB_MODEL_SGB) {
return QObject::tr("SGB");
}
}
return QObject::tr("GB"); return QObject::tr("GB");
#endif #endif
default: default:

View File

@ -31,7 +31,7 @@ enum class Endian {
}; };
QString niceSizeFormat(size_t filesize); QString niceSizeFormat(size_t filesize);
QString nicePlatformFormat(mPlatform platform); QString nicePlatformFormat(mPlatform platform, int validModels = 0);
bool convertAddress(const QHostAddress* input, Address* output); bool convertAddress(const QHostAddress* input, Address* output);