skyline/app/src/main/java/emu/skyline/loader/RomFile.kt
Willi Ye 4076d84efc
NCA decryption (#99)
* NCA decryption
* Remove unnecessary new lines
* Remove loader error dialog
* Always show ROMs
* Address CRs
* Add subtitle padding in grid mode
2020-09-14 19:23:40 +05:30

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
}