Util: Bring up MD5 and SHA-1 library and No-Intro querying
This commit is contained in:
parent
eb781d290b
commit
0e42f9d561
@ -24,6 +24,8 @@ struct mLibraryEntry {
|
|||||||
enum mPlatform platform;
|
enum mPlatform platform;
|
||||||
size_t filesize;
|
size_t filesize;
|
||||||
uint32_t crc32;
|
uint32_t crc32;
|
||||||
|
uint8_t md5[16];
|
||||||
|
uint8_t sha1[20];
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef USE_SQLITE3
|
#ifdef USE_SQLITE3
|
||||||
|
@ -34,6 +34,8 @@ struct mLibrary {
|
|||||||
"CASE WHEN :useSize THEN roms.size = :size ELSE 1 END AND " \
|
"CASE WHEN :useSize THEN roms.size = :size ELSE 1 END AND " \
|
||||||
"CASE WHEN :usePlatform THEN roms.platform = :platform ELSE 1 END AND " \
|
"CASE WHEN :usePlatform THEN roms.platform = :platform ELSE 1 END AND " \
|
||||||
"CASE WHEN :useCrc32 THEN roms.crc32 = :crc32 ELSE 1 END AND " \
|
"CASE WHEN :useCrc32 THEN roms.crc32 = :crc32 ELSE 1 END AND " \
|
||||||
|
"CASE WHEN :useMd5 THEN roms.md5 = :md5 ELSE 1 END AND " \
|
||||||
|
"CASE WHEN :useSha1 THEN roms.sha1 = :sha1 ELSE 1 END AND " \
|
||||||
"CASE WHEN :useInternalCode THEN roms.internalCode = :internalCode ELSE 1 END"
|
"CASE WHEN :useInternalCode THEN roms.internalCode = :internalCode ELSE 1 END"
|
||||||
|
|
||||||
#define CONSTRAINTS \
|
#define CONSTRAINTS \
|
||||||
@ -58,6 +60,20 @@ static void _bindConstraints(sqlite3_stmt* statement, const struct mLibraryEntry
|
|||||||
sqlite3_bind_int(statement, index, constraints->crc32);
|
sqlite3_bind_int(statement, index, constraints->crc32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (memcmp(constraints->md5, &(uint8_t[16]) {0}, 16) != 0) {
|
||||||
|
useIndex = sqlite3_bind_parameter_index(statement, ":useMd5");
|
||||||
|
index = sqlite3_bind_parameter_index(statement, ":md5");
|
||||||
|
sqlite3_bind_int(statement, useIndex, 1);
|
||||||
|
sqlite3_bind_blob(statement, index, constraints->md5, 16, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(constraints->sha1, &(uint8_t[20]) {0}, 20) != 0) {
|
||||||
|
useIndex = sqlite3_bind_parameter_index(statement, ":useSha1");
|
||||||
|
index = sqlite3_bind_parameter_index(statement, ":sha1");
|
||||||
|
sqlite3_bind_int(statement, useIndex, 1);
|
||||||
|
sqlite3_bind_blob(statement, index, constraints->sha1, 20, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (constraints->filesize) {
|
if (constraints->filesize) {
|
||||||
useIndex = sqlite3_bind_parameter_index(statement, ":useSize");
|
useIndex = sqlite3_bind_parameter_index(statement, ":useSize");
|
||||||
index = sqlite3_bind_parameter_index(statement, ":size");
|
index = sqlite3_bind_parameter_index(statement, ":size");
|
||||||
@ -139,6 +155,8 @@ struct mLibrary* mLibraryLoad(const char* path) {
|
|||||||
"\n CONSTRAINT location UNIQUE (path, rootid)"
|
"\n CONSTRAINT location UNIQUE (path, rootid)"
|
||||||
"\n );"
|
"\n );"
|
||||||
"\n CREATE INDEX IF NOT EXISTS crc32 ON roms (crc32);"
|
"\n CREATE INDEX IF NOT EXISTS crc32 ON roms (crc32);"
|
||||||
|
"\n CREATE INDEX IF NOT EXISTS md5 ON roms (md5);"
|
||||||
|
"\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', 1);"
|
||||||
@ -152,7 +170,7 @@ struct mLibrary* mLibraryLoad(const char* path) {
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char insertRom[] = "INSERT INTO roms (crc32, size, internalCode, platform) VALUES (:crc32, :size, :internalCode, :platform);";
|
static const char insertRom[] = "INSERT INTO roms (crc32, md5, sha1, size, internalCode, platform) VALUES (:crc32, :md5, :sha1, :size, :internalCode, :platform);";
|
||||||
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;
|
||||||
}
|
}
|
||||||
@ -297,6 +315,8 @@ bool _mLibraryAddEntry(struct mLibrary* library, const char* filename, const cha
|
|||||||
snprintf(entry.internalCode, sizeof(entry.internalCode), "%s-%s", info.system, info.code);
|
snprintf(entry.internalCode, sizeof(entry.internalCode), "%s-%s", info.system, info.code);
|
||||||
strlcpy(entry.internalTitle, info.title, sizeof(entry.internalTitle));
|
strlcpy(entry.internalTitle, info.title, sizeof(entry.internalTitle));
|
||||||
core->checksum(core, &entry.crc32, mCHECKSUM_CRC32);
|
core->checksum(core, &entry.crc32, mCHECKSUM_CRC32);
|
||||||
|
core->checksum(core, &entry.md5, mCHECKSUM_MD5);
|
||||||
|
core->checksum(core, &entry.sha1, mCHECKSUM_SHA1);
|
||||||
entry.platform = core->platform(core);
|
entry.platform = core->platform(core);
|
||||||
entry.title = NULL;
|
entry.title = NULL;
|
||||||
entry.base = base;
|
entry.base = base;
|
||||||
@ -402,10 +422,28 @@ size_t mLibraryGetEntries(struct mLibrary* library, struct mLibraryListing* out,
|
|||||||
int i;
|
int i;
|
||||||
for (i = 0; i < nCols; ++i) {
|
for (i = 0; i < nCols; ++i) {
|
||||||
const char* colName = sqlite3_column_name(library->select, i);
|
const char* colName = sqlite3_column_name(library->select, i);
|
||||||
if (strcmp(colName, "crc32") == 0) {
|
if (strcmp(colName, "sha1") == 0) {
|
||||||
|
const void* buf = sqlite3_column_blob(library->select, i);
|
||||||
|
if (buf && sqlite3_column_bytes(library->select, i) == sizeof(entry->sha1)) {
|
||||||
|
memcpy(entry->sha1, buf, sizeof(entry->sha1));
|
||||||
|
struct NoIntroGame game;
|
||||||
|
if (!entry->title && NoIntroDBLookupGameBySHA1(library->gameDB, entry->sha1, &game)) {
|
||||||
|
entry->title = strdup(game.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (strcmp(colName, "md5") == 0) {
|
||||||
|
const void* buf = sqlite3_column_blob(library->select, i);
|
||||||
|
if (buf && sqlite3_column_bytes(library->select, i) == sizeof(entry->md5)) {
|
||||||
|
memcpy(entry->md5, buf, sizeof(entry->md5));
|
||||||
|
struct NoIntroGame game;
|
||||||
|
if (!entry->title && NoIntroDBLookupGameByMD5(library->gameDB, entry->md5, &game)) {
|
||||||
|
entry->title = strdup(game.name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (strcmp(colName, "crc32") == 0) {
|
||||||
entry->crc32 = sqlite3_column_int(library->select, i);
|
entry->crc32 = sqlite3_column_int(library->select, i);
|
||||||
struct NoIntroGame game;
|
struct NoIntroGame game;
|
||||||
if (NoIntroDBLookupGameByCRC(library->gameDB, entry->crc32, &game)) {
|
if (!entry->title && NoIntroDBLookupGameByCRC(library->gameDB, entry->crc32, &game)) {
|
||||||
entry->title = strdup(game.name);
|
entry->title = strdup(game.name);
|
||||||
}
|
}
|
||||||
} else if (strcmp(colName, "platform") == 0) {
|
} else if (strcmp(colName, "platform") == 0) {
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
struct NoIntroDB {
|
struct NoIntroDB {
|
||||||
sqlite3* db;
|
sqlite3* db;
|
||||||
sqlite3_stmt* crc32;
|
sqlite3_stmt* crc32;
|
||||||
|
sqlite3_stmt* md5;
|
||||||
|
sqlite3_stmt* sha1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct NoIntroDB* NoIntroDBLoad(const char* path) {
|
struct NoIntroDB* NoIntroDBLoad(const char* path) {
|
||||||
@ -54,8 +56,18 @@ struct NoIntroDB* NoIntroDBLoad(const char* path) {
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char selectRom[] = "SELECT * FROM games JOIN roms USING (gid) WHERE roms.crc32 = ?;";
|
static const char selectCrc32[] = "SELECT games.name, roms.name, size, crc32, md5, sha1, flags FROM games JOIN roms USING (gid) WHERE roms.crc32 = ?;";
|
||||||
if (sqlite3_prepare_v2(db->db, selectRom, -1, &db->crc32, NULL)) {
|
if (sqlite3_prepare_v2(db->db, selectCrc32, -1, &db->crc32, NULL)) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char selectMd5[] = "SELECT games.name, roms.name, size, crc32, md5, sha1, flags FROM games JOIN roms USING (gid) WHERE roms.md5 = ?;";
|
||||||
|
if (sqlite3_prepare_v2(db->db, selectMd5, -1, &db->md5, NULL)) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char selectSha1[] = "SELECT games.name, roms.name, size, crc32, md5, sha1, flags FROM games JOIN roms USING (gid) WHERE roms.sha1 = ?;";
|
||||||
|
if (sqlite3_prepare_v2(db->db, selectSha1, -1, &db->sha1, NULL)) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,12 +312,34 @@ void NoIntroDBDestroy(struct NoIntroDB* db) {
|
|||||||
if (db->crc32) {
|
if (db->crc32) {
|
||||||
sqlite3_finalize(db->crc32);
|
sqlite3_finalize(db->crc32);
|
||||||
}
|
}
|
||||||
|
if (db->md5) {
|
||||||
|
sqlite3_finalize(db->md5);
|
||||||
|
}
|
||||||
|
if (db->sha1) {
|
||||||
|
sqlite3_finalize(db->sha1);
|
||||||
|
}
|
||||||
if (db->db) {
|
if (db->db) {
|
||||||
sqlite3_close(db->db);
|
sqlite3_close(db->db);
|
||||||
}
|
}
|
||||||
free(db);
|
free(db);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _extractGame(sqlite3_stmt* stmt, struct NoIntroGame* game) {
|
||||||
|
game->name = (const char*) sqlite3_column_text(stmt, 0);
|
||||||
|
game->romName = (const char*) sqlite3_column_text(stmt, 1);
|
||||||
|
game->size = sqlite3_column_int(stmt, 2);
|
||||||
|
game->crc32 = sqlite3_column_int(stmt, 3);
|
||||||
|
const void* buf = sqlite3_column_blob(stmt, 4);
|
||||||
|
if (buf && sqlite3_column_bytes(stmt, 4) == sizeof(game->md5)) {
|
||||||
|
memcpy(game->md5, buf, sizeof(game->md5));
|
||||||
|
}
|
||||||
|
buf = sqlite3_column_blob(stmt, 5);
|
||||||
|
if (buf && sqlite3_column_bytes(stmt, 5) == sizeof(game->sha1)) {
|
||||||
|
memcpy(game->sha1, buf, sizeof(game->sha1));
|
||||||
|
}
|
||||||
|
game->verified = sqlite3_column_int(stmt, 6);
|
||||||
|
}
|
||||||
|
|
||||||
bool NoIntroDBLookupGameByCRC(const struct NoIntroDB* db, uint32_t crc32, struct NoIntroGame* game) {
|
bool NoIntroDBLookupGameByCRC(const struct NoIntroDB* db, uint32_t crc32, struct NoIntroGame* game) {
|
||||||
if (!db) {
|
if (!db) {
|
||||||
return false;
|
return false;
|
||||||
@ -316,11 +350,34 @@ bool NoIntroDBLookupGameByCRC(const struct NoIntroDB* db, uint32_t crc32, struct
|
|||||||
if (sqlite3_step(db->crc32) != SQLITE_ROW) {
|
if (sqlite3_step(db->crc32) != SQLITE_ROW) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
game->name = (const char*) sqlite3_column_text(db->crc32, 1);
|
_extractGame(db->crc32, game);
|
||||||
game->romName = (const char*) sqlite3_column_text(db->crc32, 3);
|
return true;
|
||||||
game->size = sqlite3_column_int(db->crc32, 4);
|
}
|
||||||
game->crc32 = sqlite3_column_int(db->crc32, 5);
|
|
||||||
// TODO: md5/sha1
|
bool NoIntroDBLookupGameByMD5(const struct NoIntroDB* db, const uint8_t* md5, struct NoIntroGame* game) {
|
||||||
game->verified = sqlite3_column_int(db->crc32, 8);
|
if (!db) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sqlite3_clear_bindings(db->md5);
|
||||||
|
sqlite3_reset(db->md5);
|
||||||
|
sqlite3_bind_blob(db->md5, 1, md5, 16, NULL);
|
||||||
|
if (sqlite3_step(db->md5) != SQLITE_ROW) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_extractGame(db->md5, game);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool NoIntroDBLookupGameBySHA1(const struct NoIntroDB* db, const uint8_t* sha1, struct NoIntroGame* game) {
|
||||||
|
if (!db) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sqlite3_clear_bindings(db->sha1);
|
||||||
|
sqlite3_reset(db->sha1);
|
||||||
|
sqlite3_bind_blob(db->sha1, 1, sha1, 20, NULL);
|
||||||
|
if (sqlite3_step(db->sha1) != SQLITE_ROW) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_extractGame(db->sha1, game);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,8 @@ struct NoIntroDB* NoIntroDBLoad(const char* path);
|
|||||||
bool NoIntroDBLoadClrMamePro(struct NoIntroDB* db, struct VFile* vf);
|
bool NoIntroDBLoadClrMamePro(struct NoIntroDB* db, struct VFile* vf);
|
||||||
void NoIntroDBDestroy(struct NoIntroDB* db);
|
void NoIntroDBDestroy(struct NoIntroDB* db);
|
||||||
bool NoIntroDBLookupGameByCRC(const struct NoIntroDB* db, uint32_t crc32, struct NoIntroGame* game);
|
bool NoIntroDBLookupGameByCRC(const struct NoIntroDB* db, uint32_t crc32, struct NoIntroGame* game);
|
||||||
|
bool NoIntroDBLookupGameByMD5(const struct NoIntroDB* db, const uint8_t* md5, struct NoIntroGame* game);
|
||||||
|
bool NoIntroDBLookupGameBySHA1(const struct NoIntroDB* db, const uint8_t* sha1, struct NoIntroGame* game);
|
||||||
|
|
||||||
CXX_GUARD_END
|
CXX_GUARD_END
|
||||||
|
|
||||||
|
@ -48,32 +48,42 @@ ROMInfo::ROMInfo(std::shared_ptr<CoreController> controller, QWidget* parent)
|
|||||||
|
|
||||||
if (crc32) {
|
if (crc32) {
|
||||||
m_ui.crc->setText(QString::number(crc32, 16));
|
m_ui.crc->setText(QString::number(crc32, 16));
|
||||||
#ifdef USE_SQLITE3
|
|
||||||
if (db) {
|
|
||||||
NoIntroGame game{};
|
|
||||||
if (NoIntroDBLookupGameByCRC(db, crc32, &game)) {
|
|
||||||
m_ui.name->setText(game.name);
|
|
||||||
} else {
|
|
||||||
m_ui.name->setText(tr("(unknown)"));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
m_ui.name->setText(tr("(no database present)"));
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
m_ui.name->hide();
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
m_ui.crc->setText(tr("(unknown)"));
|
m_ui.crc->setText(tr("(unknown)"));
|
||||||
m_ui.name->setText(tr("(unknown)"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_ui.md5->setText(QString::asprintf("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
if (memcmp(md5, &(const uint8_t[16]) {}, 16) != 0) {
|
||||||
md5[0x0], md5[0x1], md5[0x2], md5[0x3], md5[0x4], md5[0x5], md5[0x6], md5[0x7],
|
m_ui.md5->setText(QString::asprintf("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||||
md5[0x8], md5[0x9], md5[0xA], md5[0xB], md5[0xC], md5[0xD], md5[0xE], md5[0xF]));
|
md5[0x0], md5[0x1], md5[0x2], md5[0x3], md5[0x4], md5[0x5], md5[0x6], md5[0x7],
|
||||||
|
md5[0x8], md5[0x9], md5[0xA], md5[0xB], md5[0xC], md5[0xD], md5[0xE], md5[0xF]));
|
||||||
|
} else {
|
||||||
|
m_ui.md5->setText(tr("(unknown)"));
|
||||||
|
}
|
||||||
|
|
||||||
m_ui.sha1->setText(QString::asprintf("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
if (memcmp(sha1, &(const uint8_t[20]) {}, 20) != 0) {
|
||||||
sha1[ 0], sha1[ 1], sha1[ 2], sha1[ 3], sha1[ 4], sha1[ 5], sha1[ 6], sha1[ 7], sha1[ 8], sha1[ 9],
|
m_ui.sha1->setText(QString::asprintf("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
|
||||||
sha1[10], sha1[11], sha1[12], sha1[13], sha1[14], sha1[15], sha1[16], sha1[17], sha1[18], sha1[19]));
|
sha1[ 0], sha1[ 1], sha1[ 2], sha1[ 3], sha1[ 4], sha1[ 5], sha1[ 6], sha1[ 7], sha1[ 8], sha1[ 9],
|
||||||
|
sha1[10], sha1[11], sha1[12], sha1[13], sha1[14], sha1[15], sha1[16], sha1[17], sha1[18], sha1[19]));
|
||||||
|
} else {
|
||||||
|
m_ui.sha1->setText(tr("(unknown)"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_SQLITE3
|
||||||
|
if (db) {
|
||||||
|
NoIntroGame game{};
|
||||||
|
if (memcmp(sha1, &(const uint8_t[20]) {}, 20) != 0 && NoIntroDBLookupGameBySHA1(db, sha1, &game)) {
|
||||||
|
m_ui.name->setText(game.name);
|
||||||
|
} else if (crc32 && NoIntroDBLookupGameByCRC(db, crc32, &game)) {
|
||||||
|
m_ui.name->setText(game.name);
|
||||||
|
} else {
|
||||||
|
m_ui.name->setText(tr("(unknown)"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m_ui.name->setText(tr("(no database present)"));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
m_ui.name->hide();
|
||||||
|
#endif
|
||||||
|
|
||||||
QString savePath = controller->savePath();
|
QString savePath = controller->savePath();
|
||||||
if (!savePath.isEmpty()) {
|
if (!savePath.isEmpty()) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user