mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-06-02 10:18:46 +02:00
4076d84efc
* NCA decryption * Remove unnecessary new lines * Remove loader error dialog * Always show ROMs * Address CRs * Add subtitle padding in grid mode
121 lines
3.9 KiB
Kotlin
121 lines
3.9 KiB
Kotlin
/*
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
* Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
|
*/
|
|
|
|
package emu.skyline.loader
|
|
|
|
import android.content.ContentResolver
|
|
import android.content.Context
|
|
import android.graphics.Bitmap
|
|
import android.graphics.BitmapFactory
|
|
import android.net.Uri
|
|
import android.provider.OpenableColumns
|
|
import java.io.Serializable
|
|
import java.util.*
|
|
|
|
/**
|
|
* An enumeration of all supported ROM formats
|
|
*/
|
|
enum class RomFormat(val format : Int) {
|
|
NRO(0),
|
|
NSO(1),
|
|
NCA(2),
|
|
XCI(3),
|
|
NSP(4),
|
|
}
|
|
|
|
/**
|
|
* This resolves the format of a ROM from it's URI so we can determine formats for ROMs launched from arbitrary locations
|
|
*
|
|
* @param uri The URL of the ROM
|
|
* @param contentResolver The instance of ContentResolver associated with the current context
|
|
*/
|
|
fun getRomFormat(uri : Uri, contentResolver : ContentResolver) : RomFormat {
|
|
var uriStr = ""
|
|
contentResolver.query(uri, null, null, null, null)?.use { cursor ->
|
|
val nameIndex : Int = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
|
|
cursor.moveToFirst()
|
|
uriStr = cursor.getString(nameIndex)
|
|
}
|
|
return RomFormat.valueOf(uriStr.substring(uriStr.lastIndexOf(".") + 1).toUpperCase(Locale.ROOT))
|
|
}
|
|
|
|
/**
|
|
* An enumeration of all possible results when populating [RomFile]
|
|
*/
|
|
enum class LoaderResult(val value : Int) {
|
|
Success(0),
|
|
ParsingError(1),
|
|
MissingHeaderKey(2),
|
|
MissingTitleKey(3),
|
|
MissingTitleKek(4),
|
|
MissingKeyArea(5);
|
|
|
|
companion object {
|
|
fun get(value : Int) = values().first { value == it.value }
|
|
}
|
|
}
|
|
|
|
/**
|
|
* This class is used to hold an application's metadata in a serializable way
|
|
*/
|
|
class AppEntry(val name : String, val author : String?, val icon : Bitmap?, val format : RomFormat, val uri : Uri, val loaderResult : LoaderResult) : Serializable {
|
|
constructor(context : Context, format : RomFormat, uri : Uri, loaderResult : LoaderResult) : this(context.contentResolver.query(uri, null, null, null, null)?.use { cursor ->
|
|
val nameIndex : Int = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
|
|
cursor.moveToFirst()
|
|
cursor.getString(nameIndex)
|
|
}!!.dropLast(format.name.length + 1), null, null, format, uri, loaderResult)
|
|
}
|
|
|
|
/**
|
|
* This class is used as interface between libskyline and Kotlin for loaders
|
|
*/
|
|
internal class RomFile(context : Context, format : RomFormat, uri : Uri) {
|
|
/**
|
|
* @note This field is filled in by native code
|
|
*/
|
|
private var applicationName : String? = null
|
|
|
|
/**
|
|
* @note This field is filled in by native code
|
|
*/
|
|
private var applicationAuthor : String? = null
|
|
|
|
/**
|
|
* @note This field is filled in by native code
|
|
*/
|
|
private var rawIcon : ByteArray? = null
|
|
|
|
val appEntry : AppEntry
|
|
|
|
var result = LoaderResult.Success
|
|
|
|
val valid : Boolean
|
|
get() = result == LoaderResult.Success
|
|
|
|
init {
|
|
System.loadLibrary("skyline")
|
|
|
|
context.contentResolver.openFileDescriptor(uri, "r")!!.use {
|
|
result = LoaderResult.get(populate(format.ordinal, it.fd, context.filesDir.canonicalPath + "/"))
|
|
}
|
|
|
|
appEntry = applicationName?.let { name ->
|
|
applicationAuthor?.let { author ->
|
|
rawIcon?.let { icon ->
|
|
AppEntry(name, author, BitmapFactory.decodeByteArray(icon, 0, icon.size), format, uri, result)
|
|
}
|
|
}
|
|
} ?: AppEntry(context, format, uri, result)
|
|
}
|
|
|
|
/**
|
|
* Parses ROM and writes its metadata to [applicationName], [applicationAuthor] and [rawIcon]
|
|
* @param format The format of the ROM
|
|
* @param romFd A file descriptor of the ROM
|
|
* @param appFilesPath Path to internal app data storage, needed to read imported keys
|
|
* @return A pointer to the newly allocated object, or 0 if the ROM is invalid
|
|
*/
|
|
private external fun populate(format : Int, romFd : Int, appFilesPath : String) : Int
|
|
} |