feat(script): add options support

This commit is contained in:
Skylot
2022-07-21 20:39:05 +01:00
parent d9af91bc4d
commit 278d7fa3f9
10 changed files with 237 additions and 28 deletions
@@ -0,0 +1,94 @@
package jadx.plugins.script.runtime.data
import jadx.api.plugins.options.OptionDescription
import jadx.api.plugins.options.OptionDescription.OptionType
import jadx.api.plugins.options.impl.JadxOptionDescription
import jadx.plugins.script.runtime.JadxScriptInstance
data class JadxScriptAllOptions(
val values: Map<String, String>,
val descriptions: MutableList<OptionDescription> = mutableListOf()
)
class ScriptOption<T>(
val name: String,
val id: String,
private val getter: () -> T,
) {
private var validate: ((T) -> Boolean)? = null
val value: T
get() {
val v = getter.invoke()
validate?.let { predicate ->
if (!predicate.invoke(v)) {
throw IllegalArgumentException("Invalid value '$v' for option $id")
}
}
return v
}
fun validate(predicate: (T) -> Boolean): ScriptOption<T> {
validate = predicate
return this
}
}
class JadxScriptOptions(
private val jadx: JadxScriptInstance,
private val options: JadxScriptAllOptions
) {
fun <T> register(
name: String,
desc: String,
values: List<String>,
defaultValue: String,
type: OptionType = OptionType.STRING,
convert: (String?) -> T
): ScriptOption<T> {
val id = "jadx-script.${jadx.scriptName}.$name"
options.descriptions.add(JadxOptionDescription(id, desc, defaultValue, values, type))
return ScriptOption(name, id) { convert.invoke(options.values[id]) }
}
fun registerString(
name: String,
desc: String = "",
values: List<String> = emptyList(),
defaultValue: String = ""
): ScriptOption<String> {
return register(name, desc, values, defaultValue) { value ->
if (value == null) {
defaultValue
} else {
if (values.isEmpty() || values.contains(value)) {
value
} else {
throw IllegalArgumentException("Unknown value '$value' for option '$name', expect one of $values")
}
}
}
}
fun registerYesNo(name: String, desc: String = "", defaultValue: Boolean = false): ScriptOption<Boolean> {
val defStr = if (defaultValue) "yes" else "no"
return register(name, desc, listOf("yes", "no"), defStr, OptionType.BOOLEAN) { value ->
when (value) {
null -> defaultValue
"yes", "true" -> true
"no", "false" -> false
else -> throw IllegalArgumentException("Unknown value '$value' for option '$name', expect: 'yes' or 'no'")
}
}
}
fun registerInt(name: String, desc: String = "", defaultValue: Int = 0): ScriptOption<Int> {
return register(name, desc, emptyList(), defaultValue.toString(), OptionType.NUMBER) { value ->
when (value) {
null -> defaultValue
else -> value.toInt()
}
}
}
}
@@ -31,6 +31,7 @@ open class JadxScriptBaseClass(private val scriptData: JadxScriptData) {
class JadxScriptData(
val jadxInstance: JadxDecompiler,
val pluginContext: JadxPluginContext,
val options: JadxScriptAllOptions,
val scriptFile: File
) {
val afterLoad: MutableList<() -> Unit> = ArrayList()
@@ -44,6 +45,7 @@ class JadxScriptInstance(
) {
private val decompiler = scriptData.jadxInstance
val options: JadxScriptOptions by lazy { JadxScriptOptions(this, scriptData.options) }
val rename: RenamePass by lazy { RenamePass(this) }
val stages: Stages by lazy { Stages(this) }
val replace: Replace by lazy { Replace(this) }