committed by
bunnei
2 changed files with 260 additions and 275 deletions
-
275src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GameDatabase.java
-
260src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GameDatabase.kt
@ -1,275 +0,0 @@ |
|||||
package org.yuzu.yuzu_emu.model; |
|
||||
|
|
||||
import android.content.ContentValues; |
|
||||
import android.content.Context; |
|
||||
import android.database.Cursor; |
|
||||
import android.database.sqlite.SQLiteDatabase; |
|
||||
import android.database.sqlite.SQLiteOpenHelper; |
|
||||
import android.net.Uri; |
|
||||
|
|
||||
import org.yuzu.yuzu_emu.NativeLibrary; |
|
||||
import org.yuzu.yuzu_emu.utils.FileUtil; |
|
||||
import org.yuzu.yuzu_emu.utils.Log; |
|
||||
|
|
||||
import java.io.File; |
|
||||
import java.util.Arrays; |
|
||||
import java.util.HashSet; |
|
||||
import java.util.Set; |
|
||||
|
|
||||
import rx.Observable; |
|
||||
|
|
||||
/** |
|
||||
* A helper class that provides several utilities simplifying interaction with |
|
||||
* the SQLite database. |
|
||||
*/ |
|
||||
public final class GameDatabase extends SQLiteOpenHelper { |
|
||||
public static final int COLUMN_DB_ID = 0; |
|
||||
public static final int GAME_COLUMN_PATH = 1; |
|
||||
public static final int GAME_COLUMN_TITLE = 2; |
|
||||
public static final int GAME_COLUMN_DESCRIPTION = 3; |
|
||||
public static final int GAME_COLUMN_REGIONS = 4; |
|
||||
public static final int GAME_COLUMN_GAME_ID = 5; |
|
||||
public static final int GAME_COLUMN_CAPTION = 6; |
|
||||
public static final int FOLDER_COLUMN_PATH = 1; |
|
||||
public static final String KEY_DB_ID = "_id"; |
|
||||
public static final String KEY_GAME_PATH = "path"; |
|
||||
public static final String KEY_GAME_TITLE = "title"; |
|
||||
public static final String KEY_GAME_DESCRIPTION = "description"; |
|
||||
public static final String KEY_GAME_REGIONS = "regions"; |
|
||||
public static final String KEY_GAME_ID = "game_id"; |
|
||||
public static final String KEY_GAME_COMPANY = "company"; |
|
||||
public static final String KEY_FOLDER_PATH = "path"; |
|
||||
public static final String TABLE_NAME_FOLDERS = "folders"; |
|
||||
public static final String TABLE_NAME_GAMES = "games"; |
|
||||
private static final int DB_VERSION = 2; |
|
||||
private static final String TYPE_PRIMARY = " INTEGER PRIMARY KEY"; |
|
||||
private static final String TYPE_INTEGER = " INTEGER"; |
|
||||
private static final String TYPE_STRING = " TEXT"; |
|
||||
|
|
||||
private static final String CONSTRAINT_UNIQUE = " UNIQUE"; |
|
||||
|
|
||||
private static final String SEPARATOR = ", "; |
|
||||
|
|
||||
private static final String SQL_CREATE_GAMES = "CREATE TABLE " + TABLE_NAME_GAMES + "(" |
|
||||
+ KEY_DB_ID + TYPE_PRIMARY + SEPARATOR |
|
||||
+ KEY_GAME_PATH + TYPE_STRING + SEPARATOR |
|
||||
+ KEY_GAME_TITLE + TYPE_STRING + SEPARATOR |
|
||||
+ KEY_GAME_DESCRIPTION + TYPE_STRING + SEPARATOR |
|
||||
+ KEY_GAME_REGIONS + TYPE_STRING + SEPARATOR |
|
||||
+ KEY_GAME_ID + TYPE_STRING + SEPARATOR |
|
||||
+ KEY_GAME_COMPANY + TYPE_STRING + ")"; |
|
||||
|
|
||||
private static final String SQL_CREATE_FOLDERS = "CREATE TABLE " + TABLE_NAME_FOLDERS + "(" |
|
||||
+ KEY_DB_ID + TYPE_PRIMARY + SEPARATOR |
|
||||
+ KEY_FOLDER_PATH + TYPE_STRING + CONSTRAINT_UNIQUE + ")"; |
|
||||
|
|
||||
private static final String SQL_DELETE_FOLDERS = "DROP TABLE IF EXISTS " + TABLE_NAME_FOLDERS; |
|
||||
private static final String SQL_DELETE_GAMES = "DROP TABLE IF EXISTS " + TABLE_NAME_GAMES; |
|
||||
private final Context context; |
|
||||
|
|
||||
public GameDatabase(Context context) { |
|
||||
// Superclass constructor builds a database or uses an existing one. |
|
||||
super(context, "games.db", null, DB_VERSION); |
|
||||
this.context = context; |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void onCreate(SQLiteDatabase database) { |
|
||||
Log.debug("[GameDatabase] GameDatabase - Creating database..."); |
|
||||
|
|
||||
execSqlAndLog(database, SQL_CREATE_GAMES); |
|
||||
execSqlAndLog(database, SQL_CREATE_FOLDERS); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void onDowngrade(SQLiteDatabase database, int oldVersion, int newVersion) { |
|
||||
Log.verbose("[GameDatabase] Downgrades not supporting, clearing databases.."); |
|
||||
execSqlAndLog(database, SQL_DELETE_FOLDERS); |
|
||||
execSqlAndLog(database, SQL_CREATE_FOLDERS); |
|
||||
|
|
||||
execSqlAndLog(database, SQL_DELETE_GAMES); |
|
||||
execSqlAndLog(database, SQL_CREATE_GAMES); |
|
||||
} |
|
||||
|
|
||||
@Override |
|
||||
public void onUpgrade(SQLiteDatabase database, int oldVersion, int newVersion) { |
|
||||
Log.info("[GameDatabase] Upgrading database from schema version " + oldVersion + " to " + |
|
||||
newVersion); |
|
||||
|
|
||||
// Delete all the games |
|
||||
execSqlAndLog(database, SQL_DELETE_GAMES); |
|
||||
execSqlAndLog(database, SQL_CREATE_GAMES); |
|
||||
} |
|
||||
|
|
||||
public void resetDatabase(SQLiteDatabase database) { |
|
||||
execSqlAndLog(database, SQL_DELETE_FOLDERS); |
|
||||
execSqlAndLog(database, SQL_CREATE_FOLDERS); |
|
||||
|
|
||||
execSqlAndLog(database, SQL_DELETE_GAMES); |
|
||||
execSqlAndLog(database, SQL_CREATE_GAMES); |
|
||||
} |
|
||||
|
|
||||
public void scanLibrary(SQLiteDatabase database) { |
|
||||
// Before scanning known folders, go through the game table and remove any entries for which the file itself is missing. |
|
||||
Cursor fileCursor = database.query(TABLE_NAME_GAMES, |
|
||||
null, // Get all columns. |
|
||||
null, // Get all rows. |
|
||||
null, |
|
||||
null, // No grouping. |
|
||||
null, |
|
||||
null); // Order of games is irrelevant. |
|
||||
|
|
||||
// Possibly overly defensive, but ensures that moveToNext() does not skip a row. |
|
||||
fileCursor.moveToPosition(-1); |
|
||||
|
|
||||
while (fileCursor.moveToNext()) { |
|
||||
String gamePath = fileCursor.getString(GAME_COLUMN_PATH); |
|
||||
File game = new File(gamePath); |
|
||||
|
|
||||
if (!game.exists()) { |
|
||||
database.delete(TABLE_NAME_GAMES, |
|
||||
KEY_DB_ID + " = ?", |
|
||||
new String[]{Long.toString(fileCursor.getLong(COLUMN_DB_ID))}); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
// Get a cursor listing all the folders the user has added to the library. |
|
||||
Cursor folderCursor = database.query(TABLE_NAME_FOLDERS, |
|
||||
null, // Get all columns. |
|
||||
null, // Get all rows. |
|
||||
null, |
|
||||
null, // No grouping. |
|
||||
null, |
|
||||
null); // Order of folders is irrelevant. |
|
||||
|
|
||||
Set<String> allowedExtensions = new HashSet<String>(Arrays.asList( |
|
||||
".xci", ".nsp", ".nca", ".nro")); |
|
||||
|
|
||||
// Possibly overly defensive, but ensures that moveToNext() does not skip a row. |
|
||||
folderCursor.moveToPosition(-1); |
|
||||
|
|
||||
// Iterate through all results of the DB query (i.e. all folders in the library.) |
|
||||
while (folderCursor.moveToNext()) { |
|
||||
String folderPath = folderCursor.getString(FOLDER_COLUMN_PATH); |
|
||||
|
|
||||
Uri folderUri = Uri.parse(folderPath); |
|
||||
// If the folder is empty because it no longer exists, remove it from the library. |
|
||||
if (FileUtil.listFiles(context, folderUri).length == 0) { |
|
||||
Log.error( |
|
||||
"[GameDatabase] Folder no longer exists. Removing from the library: " + folderPath); |
|
||||
database.delete(TABLE_NAME_FOLDERS, |
|
||||
KEY_DB_ID + " = ?", |
|
||||
new String[]{Long.toString(folderCursor.getLong(COLUMN_DB_ID))}); |
|
||||
} |
|
||||
|
|
||||
this.addGamesRecursive(database, folderUri, allowedExtensions, 3); |
|
||||
} |
|
||||
|
|
||||
fileCursor.close(); |
|
||||
folderCursor.close(); |
|
||||
|
|
||||
database.close(); |
|
||||
} |
|
||||
|
|
||||
private void addGamesRecursive(SQLiteDatabase database, Uri parent, Set<String> allowedExtensions, int depth) { |
|
||||
if (depth <= 0) { |
|
||||
return; |
|
||||
} |
|
||||
|
|
||||
// Ensure keys are loaded so that ROM metadata can be decrypted. |
|
||||
NativeLibrary.ReloadKeys(); |
|
||||
|
|
||||
MinimalDocumentFile[] children = FileUtil.listFiles(context, parent); |
|
||||
for (MinimalDocumentFile file : children) { |
|
||||
if (file.isDirectory()) { |
|
||||
Set<String> newExtensions = new HashSet<>(Arrays.asList( |
|
||||
".xci", ".nsp", ".nca", ".nro")); |
|
||||
this.addGamesRecursive(database, file.getUri(), newExtensions, depth - 1); |
|
||||
} else { |
|
||||
String filename = file.getUri().toString(); |
|
||||
|
|
||||
int extensionStart = filename.lastIndexOf('.'); |
|
||||
if (extensionStart > 0) { |
|
||||
String fileExtension = filename.substring(extensionStart); |
|
||||
|
|
||||
// Check that the file has an extension we care about before trying to read out of it. |
|
||||
if (allowedExtensions.contains(fileExtension.toLowerCase())) { |
|
||||
attemptToAddGame(database, filename); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private static void attemptToAddGame(SQLiteDatabase database, String filePath) { |
|
||||
String name = NativeLibrary.GetTitle(filePath); |
|
||||
|
|
||||
// If the game's title field is empty, use the filename. |
|
||||
if (name.isEmpty()) { |
|
||||
name = filePath.substring(filePath.lastIndexOf("/") + 1); |
|
||||
} |
|
||||
|
|
||||
String gameId = NativeLibrary.GetGameId(filePath); |
|
||||
|
|
||||
// If the game's ID field is empty, use the filename without extension. |
|
||||
if (gameId.isEmpty()) { |
|
||||
gameId = filePath.substring(filePath.lastIndexOf("/") + 1, |
|
||||
filePath.lastIndexOf(".")); |
|
||||
} |
|
||||
|
|
||||
ContentValues game = Game.asContentValues(name, |
|
||||
NativeLibrary.GetDescription(filePath).replace("\n", " "), |
|
||||
NativeLibrary.GetRegions(filePath), |
|
||||
filePath, |
|
||||
gameId, |
|
||||
NativeLibrary.GetCompany(filePath)); |
|
||||
|
|
||||
// Try to update an existing game first. |
|
||||
int rowsMatched = database.update(TABLE_NAME_GAMES, // Which table to update. |
|
||||
game, |
|
||||
// The values to fill the row with. |
|
||||
KEY_GAME_ID + " = ?", |
|
||||
// The WHERE clause used to find the right row. |
|
||||
new String[]{game.getAsString( |
|
||||
KEY_GAME_ID)}); // The ? in WHERE clause is replaced with this, |
|
||||
// which is provided as an array because there |
|
||||
// could potentially be more than one argument. |
|
||||
|
|
||||
// If update fails, insert a new game instead. |
|
||||
if (rowsMatched == 0) { |
|
||||
Log.verbose("[GameDatabase] Adding game: " + game.getAsString(KEY_GAME_TITLE)); |
|
||||
database.insert(TABLE_NAME_GAMES, null, game); |
|
||||
} else { |
|
||||
Log.verbose("[GameDatabase] Updated game: " + game.getAsString(KEY_GAME_TITLE)); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
public Observable<Cursor> getGames() { |
|
||||
return Observable.create(subscriber -> |
|
||||
{ |
|
||||
Log.info("[GameDatabase] Reading games list..."); |
|
||||
|
|
||||
SQLiteDatabase database = getReadableDatabase(); |
|
||||
Cursor resultCursor = database.query( |
|
||||
TABLE_NAME_GAMES, |
|
||||
null, |
|
||||
null, |
|
||||
null, |
|
||||
null, |
|
||||
null, |
|
||||
KEY_GAME_TITLE + " ASC" |
|
||||
); |
|
||||
|
|
||||
// Pass the result cursor to the consumer. |
|
||||
subscriber.onNext(resultCursor); |
|
||||
|
|
||||
// Tell the consumer we're done; it will unsubscribe implicitly. |
|
||||
subscriber.onCompleted(); |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
private void execSqlAndLog(SQLiteDatabase database, String sql) { |
|
||||
Log.verbose("[GameDatabase] Executing SQL: " + sql); |
|
||||
database.execSQL(sql); |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,260 @@ |
|||||
|
package org.yuzu.yuzu_emu.model |
||||
|
|
||||
|
import android.content.Context |
||||
|
import android.database.Cursor |
||||
|
import android.database.sqlite.SQLiteDatabase |
||||
|
import android.database.sqlite.SQLiteOpenHelper |
||||
|
import android.net.Uri |
||||
|
import org.yuzu.yuzu_emu.NativeLibrary |
||||
|
import org.yuzu.yuzu_emu.utils.FileUtil |
||||
|
import org.yuzu.yuzu_emu.utils.Log |
||||
|
import rx.Observable |
||||
|
import rx.Subscriber |
||||
|
import java.io.File |
||||
|
import java.util.* |
||||
|
|
||||
|
/** |
||||
|
* A helper class that provides several utilities simplifying interaction with |
||||
|
* the SQLite database. |
||||
|
*/ |
||||
|
class GameDatabase(private val context: Context) : |
||||
|
SQLiteOpenHelper(context, "games.db", null, DB_VERSION) { |
||||
|
override fun onCreate(database: SQLiteDatabase) { |
||||
|
Log.debug("[GameDatabase] GameDatabase - Creating database...") |
||||
|
execSqlAndLog(database, SQL_CREATE_GAMES) |
||||
|
execSqlAndLog(database, SQL_CREATE_FOLDERS) |
||||
|
} |
||||
|
|
||||
|
override fun onDowngrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) { |
||||
|
Log.verbose("[GameDatabase] Downgrades not supporting, clearing databases..") |
||||
|
execSqlAndLog(database, SQL_DELETE_FOLDERS) |
||||
|
execSqlAndLog(database, SQL_CREATE_FOLDERS) |
||||
|
execSqlAndLog(database, SQL_DELETE_GAMES) |
||||
|
execSqlAndLog(database, SQL_CREATE_GAMES) |
||||
|
} |
||||
|
|
||||
|
override fun onUpgrade(database: SQLiteDatabase, oldVersion: Int, newVersion: Int) { |
||||
|
Log.info( |
||||
|
"[GameDatabase] Upgrading database from schema version $oldVersion to $newVersion" |
||||
|
) |
||||
|
|
||||
|
// Delete all the games |
||||
|
execSqlAndLog(database, SQL_DELETE_GAMES) |
||||
|
execSqlAndLog(database, SQL_CREATE_GAMES) |
||||
|
} |
||||
|
|
||||
|
fun resetDatabase(database: SQLiteDatabase) { |
||||
|
execSqlAndLog(database, SQL_DELETE_FOLDERS) |
||||
|
execSqlAndLog(database, SQL_CREATE_FOLDERS) |
||||
|
execSqlAndLog(database, SQL_DELETE_GAMES) |
||||
|
execSqlAndLog(database, SQL_CREATE_GAMES) |
||||
|
} |
||||
|
|
||||
|
fun scanLibrary(database: SQLiteDatabase) { |
||||
|
// Before scanning known folders, go through the game table and remove any entries for which the file itself is missing. |
||||
|
val fileCursor = database.query( |
||||
|
TABLE_NAME_GAMES, |
||||
|
null, // Get all columns. |
||||
|
null, // Get all rows. |
||||
|
null, |
||||
|
null, // No grouping. |
||||
|
null, |
||||
|
null |
||||
|
) // Order of games is irrelevant. |
||||
|
|
||||
|
// Possibly overly defensive, but ensures that moveToNext() does not skip a row. |
||||
|
fileCursor.moveToPosition(-1) |
||||
|
while (fileCursor.moveToNext()) { |
||||
|
val gamePath = fileCursor.getString(GAME_COLUMN_PATH) |
||||
|
val game = File(gamePath) |
||||
|
if (!game.exists()) { |
||||
|
database.delete( |
||||
|
TABLE_NAME_GAMES, |
||||
|
"$KEY_DB_ID = ?", |
||||
|
arrayOf(fileCursor.getLong(COLUMN_DB_ID).toString()) |
||||
|
) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// Get a cursor listing all the folders the user has added to the library. |
||||
|
val folderCursor = database.query( |
||||
|
TABLE_NAME_FOLDERS, |
||||
|
null, // Get all columns. |
||||
|
null, // Get all rows. |
||||
|
null, |
||||
|
null, // No grouping. |
||||
|
null, |
||||
|
null |
||||
|
) // Order of folders is irrelevant. |
||||
|
|
||||
|
|
||||
|
// Possibly overly defensive, but ensures that moveToNext() does not skip a row. |
||||
|
folderCursor.moveToPosition(-1) |
||||
|
|
||||
|
// Iterate through all results of the DB query (i.e. all folders in the library.) |
||||
|
while (folderCursor.moveToNext()) { |
||||
|
val folderPath = folderCursor.getString(FOLDER_COLUMN_PATH) |
||||
|
val folderUri = Uri.parse(folderPath) |
||||
|
// If the folder is empty because it no longer exists, remove it from the library. |
||||
|
if (FileUtil.listFiles(context, folderUri).isEmpty()) { |
||||
|
Log.error( |
||||
|
"[GameDatabase] Folder no longer exists. Removing from the library: $folderPath" |
||||
|
) |
||||
|
database.delete( |
||||
|
TABLE_NAME_FOLDERS, |
||||
|
"$KEY_DB_ID = ?", |
||||
|
arrayOf(folderCursor.getLong(COLUMN_DB_ID).toString()) |
||||
|
) |
||||
|
} |
||||
|
addGamesRecursive(database, folderUri, Game.extensions, 3) |
||||
|
} |
||||
|
fileCursor.close() |
||||
|
folderCursor.close() |
||||
|
database.close() |
||||
|
} |
||||
|
|
||||
|
private fun addGamesRecursive( |
||||
|
database: SQLiteDatabase, |
||||
|
parent: Uri, |
||||
|
allowedExtensions: Set<String>, |
||||
|
depth: Int |
||||
|
) { |
||||
|
if (depth <= 0) |
||||
|
return |
||||
|
|
||||
|
// Ensure keys are loaded so that ROM metadata can be decrypted. |
||||
|
NativeLibrary.ReloadKeys() |
||||
|
val children = FileUtil.listFiles(context, parent) |
||||
|
for (file in children) { |
||||
|
if (file.isDirectory) { |
||||
|
addGamesRecursive(database, file.uri, Game.extensions, depth - 1) |
||||
|
} else { |
||||
|
val filename = file.uri.toString() |
||||
|
val extensionStart = filename.lastIndexOf('.') |
||||
|
if (extensionStart > 0) { |
||||
|
val fileExtension = filename.substring(extensionStart) |
||||
|
|
||||
|
// Check that the file has an extension we care about before trying to read out of it. |
||||
|
if (allowedExtensions.contains(fileExtension.lowercase(Locale.getDefault()))) { |
||||
|
attemptToAddGame(database, filename) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
// Pass the result cursor to the consumer. |
||||
|
|
||||
|
// Tell the consumer we're done; it will unsubscribe implicitly. |
||||
|
val games: Observable<Cursor?> |
||||
|
get() = Observable.create { subscriber: Subscriber<in Cursor?> -> |
||||
|
Log.info("[GameDatabase] Reading games list...") |
||||
|
val database = readableDatabase |
||||
|
val resultCursor = database.query( |
||||
|
TABLE_NAME_GAMES, |
||||
|
null, |
||||
|
null, |
||||
|
null, |
||||
|
null, |
||||
|
null, |
||||
|
"$KEY_GAME_TITLE ASC" |
||||
|
) |
||||
|
|
||||
|
// Pass the result cursor to the consumer. |
||||
|
subscriber.onNext(resultCursor) |
||||
|
|
||||
|
// Tell the consumer we're done; it will unsubscribe implicitly. |
||||
|
subscriber.onCompleted() |
||||
|
} |
||||
|
|
||||
|
private fun execSqlAndLog(database: SQLiteDatabase, sql: String) { |
||||
|
Log.verbose("[GameDatabase] Executing SQL: $sql") |
||||
|
database.execSQL(sql) |
||||
|
} |
||||
|
|
||||
|
companion object { |
||||
|
const val COLUMN_DB_ID = 0 |
||||
|
const val GAME_COLUMN_PATH = 1 |
||||
|
const val GAME_COLUMN_TITLE = 2 |
||||
|
const val GAME_COLUMN_DESCRIPTION = 3 |
||||
|
const val GAME_COLUMN_REGIONS = 4 |
||||
|
const val GAME_COLUMN_GAME_ID = 5 |
||||
|
const val GAME_COLUMN_CAPTION = 6 |
||||
|
const val FOLDER_COLUMN_PATH = 1 |
||||
|
const val KEY_DB_ID = "_id" |
||||
|
const val KEY_GAME_PATH = "path" |
||||
|
const val KEY_GAME_TITLE = "title" |
||||
|
const val KEY_GAME_DESCRIPTION = "description" |
||||
|
const val KEY_GAME_REGIONS = "regions" |
||||
|
const val KEY_GAME_ID = "game_id" |
||||
|
const val KEY_GAME_COMPANY = "company" |
||||
|
const val KEY_FOLDER_PATH = "path" |
||||
|
const val TABLE_NAME_FOLDERS = "folders" |
||||
|
const val TABLE_NAME_GAMES = "games" |
||||
|
private const val DB_VERSION = 2 |
||||
|
private const val TYPE_PRIMARY = " INTEGER PRIMARY KEY" |
||||
|
private const val TYPE_INTEGER = " INTEGER" |
||||
|
private const val TYPE_STRING = " TEXT" |
||||
|
private const val CONSTRAINT_UNIQUE = " UNIQUE" |
||||
|
private const val SEPARATOR = ", " |
||||
|
private const val SQL_CREATE_GAMES = ("CREATE TABLE " + TABLE_NAME_GAMES + "(" |
||||
|
+ KEY_DB_ID + TYPE_PRIMARY + SEPARATOR |
||||
|
+ KEY_GAME_PATH + TYPE_STRING + SEPARATOR |
||||
|
+ KEY_GAME_TITLE + TYPE_STRING + SEPARATOR |
||||
|
+ KEY_GAME_DESCRIPTION + TYPE_STRING + SEPARATOR |
||||
|
+ KEY_GAME_REGIONS + TYPE_STRING + SEPARATOR |
||||
|
+ KEY_GAME_ID + TYPE_STRING + SEPARATOR |
||||
|
+ KEY_GAME_COMPANY + TYPE_STRING + ")") |
||||
|
private const val SQL_CREATE_FOLDERS = ("CREATE TABLE " + TABLE_NAME_FOLDERS + "(" |
||||
|
+ KEY_DB_ID + TYPE_PRIMARY + SEPARATOR |
||||
|
+ KEY_FOLDER_PATH + TYPE_STRING + CONSTRAINT_UNIQUE + ")") |
||||
|
private const val SQL_DELETE_FOLDERS = "DROP TABLE IF EXISTS $TABLE_NAME_FOLDERS" |
||||
|
private const val SQL_DELETE_GAMES = "DROP TABLE IF EXISTS $TABLE_NAME_GAMES" |
||||
|
private fun attemptToAddGame(database: SQLiteDatabase, filePath: String) { |
||||
|
var name = NativeLibrary.GetTitle(filePath) |
||||
|
|
||||
|
// If the game's title field is empty, use the filename. |
||||
|
if (name.isEmpty()) { |
||||
|
name = filePath.substring(filePath.lastIndexOf("/") + 1) |
||||
|
} |
||||
|
var gameId = NativeLibrary.GetGameId(filePath) |
||||
|
|
||||
|
// If the game's ID field is empty, use the filename without extension. |
||||
|
if (gameId.isEmpty()) { |
||||
|
gameId = filePath.substring( |
||||
|
filePath.lastIndexOf("/") + 1, |
||||
|
filePath.lastIndexOf(".") |
||||
|
) |
||||
|
} |
||||
|
val game = Game.asContentValues( |
||||
|
name, |
||||
|
NativeLibrary.GetDescription(filePath).replace("\n", " "), |
||||
|
NativeLibrary.GetRegions(filePath), |
||||
|
filePath, |
||||
|
gameId, |
||||
|
NativeLibrary.GetCompany(filePath) |
||||
|
) |
||||
|
|
||||
|
// Try to update an existing game first. |
||||
|
val rowsMatched = database.update( |
||||
|
TABLE_NAME_GAMES, // Which table to update. |
||||
|
game, // The values to fill the row with. |
||||
|
"$KEY_GAME_ID = ?", arrayOf( |
||||
|
game.getAsString( |
||||
|
KEY_GAME_ID |
||||
|
) |
||||
|
) |
||||
|
) |
||||
|
// The ? in WHERE clause is replaced with this, |
||||
|
// which is provided as an array because there |
||||
|
// could potentially be more than one argument. |
||||
|
|
||||
|
// If update fails, insert a new game instead. |
||||
|
if (rowsMatched == 0) { |
||||
|
Log.verbose("[GameDatabase] Adding game: " + game.getAsString(KEY_GAME_TITLE)) |
||||
|
database.insert(TABLE_NAME_GAMES, null, game) |
||||
|
} else { |
||||
|
Log.verbose("[GameDatabase] Updated game: " + game.getAsString(KEY_GAME_TITLE)) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue