refactor: mapper

This commit is contained in:
rhunk
2023-10-08 18:04:34 +02:00
parent 7a77ea6935
commit e4443279d6
19 changed files with 283 additions and 294 deletions

View File

@ -1,9 +1,13 @@
package me.rhunk.snapenhance.mapper
import kotlin.reflect.KClass
abstract class AbstractClassMapper {
private val mappers = mutableListOf<MapperContext.() -> Unit>()
abstract class AbstractClassMapper(
vararg val dependsOn: KClass<out AbstractClassMapper> = arrayOf()
) {
abstract fun run(context: MapperContext)
fun mapper(task: MapperContext.() -> Unit) {
mappers.add(task)
}
fun run(context: MapperContext) {
mappers.forEach { it(context) }
}
}

View File

@ -56,30 +56,9 @@ class Mapper(
runBlocking {
withContext(Dispatchers.IO) {
val finishedJobs = mutableListOf<Class<*>>()
val dependentsMappers = mappers.filter { it.dependsOn.isNotEmpty() }
fun onJobFinished(mapper: AbstractClassMapper) {
finishedJobs.add(mapper.javaClass)
dependentsMappers.filter { it ->
!finishedJobs.contains(it.javaClass) &&
it.dependsOn.all {
finishedJobs.contains(it.java)
}
}.forEach {
launch {
it.run(context)
onJobFinished(it)
}
}
}
mappers.forEach { mapper ->
if (mapper.dependsOn.isNotEmpty()) return@forEach
launch {
mapper.run(context)
onJobFinished(mapper)
}
}
}

View File

@ -1,34 +1,35 @@
package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper
import me.rhunk.snapenhance.mapper.MapperContext
import me.rhunk.snapenhance.mapper.ext.getClassName
import me.rhunk.snapenhance.mapper.ext.getStaticConstructor
import me.rhunk.snapenhance.mapper.ext.isFinal
import org.jf.dexlib2.iface.instruction.formats.ArrayPayload
class BCryptClassMapper : AbstractClassMapper() {
override fun run(context: MapperContext) {
for (clazz in context.classes) {
if (!clazz.isFinal()) continue
init {
mapper {
for (clazz in classes) {
if (!clazz.isFinal()) continue
val isBcryptClass = clazz.getStaticConstructor()?.let { constructor ->
constructor.implementation?.instructions?.filterIsInstance<ArrayPayload>()?.any { it.arrayElements.size == 18 && it.arrayElements[0] == 608135816 }
}
if (isBcryptClass == true) {
val hashMethod = clazz.methods.first {
it.parameterTypes.size == 2 &&
it.parameterTypes[0] == "Ljava/lang/String;" &&
it.parameterTypes[1] == "Ljava/lang/String;" &&
it.returnType == "Ljava/lang/String;"
val isBcryptClass = clazz.getStaticConstructor()?.let { constructor ->
constructor.implementation?.instructions?.filterIsInstance<ArrayPayload>()?.any { it.arrayElements.size == 18 && it.arrayElements[0] == 608135816 }
}
context.addMapping("BCrypt",
"class" to clazz.getClassName(),
"hashMethod" to hashMethod.name
)
return
if (isBcryptClass == true) {
val hashMethod = clazz.methods.first {
it.parameterTypes.size == 2 &&
it.parameterTypes[0] == "Ljava/lang/String;" &&
it.parameterTypes[1] == "Ljava/lang/String;" &&
it.returnType == "Ljava/lang/String;"
}
addMapping("BCrypt",
"class" to clazz.getClassName(),
"hashMethod" to hashMethod.name
)
return@mapper
}
}
}
}

View File

@ -1,28 +1,29 @@
package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper
import me.rhunk.snapenhance.mapper.MapperContext
import me.rhunk.snapenhance.mapper.ext.getClassName
import me.rhunk.snapenhance.mapper.ext.getSuperClassName
import me.rhunk.snapenhance.mapper.ext.isFinal
class CallbackMapper : AbstractClassMapper() {
override fun run(context: MapperContext) {
val callbackClasses = context.classes.filter { clazz ->
if (clazz.superclass == null) return@filter false
init {
mapper {
val callbackClasses = classes.filter { clazz ->
if (clazz.superclass == null) return@filter false
val superclassName = clazz.getSuperClassName()!!
if ((!superclassName.endsWith("Callback") && !superclassName.endsWith("Delegate"))
|| superclassName.endsWith("\$Callback")) return@filter false
val superclassName = clazz.getSuperClassName()!!
if ((!superclassName.endsWith("Callback") && !superclassName.endsWith("Delegate"))
|| superclassName.endsWith("\$Callback")) return@filter false
if (clazz.getClassName().endsWith("\$CppProxy")) return@filter false
if (clazz.getClassName().endsWith("\$CppProxy")) return@filter false
val superClass = context.getClass(clazz.superclass) ?: return@filter false
!superClass.isFinal()
}.map {
it.getSuperClassName()!!.substringAfterLast("/") to it.getClassName()
val superClass = getClass(clazz.superclass) ?: return@filter false
!superClass.isFinal()
}.map {
it.getSuperClassName()!!.substringAfterLast("/") to it.getClassName()
}
addMapping("callbacks", *callbackClasses.toTypedArray())
}
context.addMapping("callbacks", *callbackClasses.toTypedArray())
}
}

View File

@ -1,7 +1,6 @@
package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper
import me.rhunk.snapenhance.mapper.MapperContext
import me.rhunk.snapenhance.mapper.ext.findConstString
import me.rhunk.snapenhance.mapper.ext.getClassName
import me.rhunk.snapenhance.mapper.ext.hasStaticConstructorString
@ -9,47 +8,49 @@ import me.rhunk.snapenhance.mapper.ext.isEnum
import java.lang.reflect.Modifier
class CompositeConfigurationProviderMapper : AbstractClassMapper() {
override fun run(context: MapperContext) {
for (classDef in context.classes) {
val constructor = classDef.methods.firstOrNull { it.name == "<init>" } ?: continue
if (constructor.parameterTypes.size == 0 || constructor.parameterTypes[0] != "Ljava/util/List;") continue
if (constructor.implementation?.findConstString("CompositeConfigurationProvider") != true) continue
init {
mapper {
for (classDef in classes) {
val constructor = classDef.methods.firstOrNull { it.name == "<init>" } ?: continue
if (constructor.parameterTypes.size == 0 || constructor.parameterTypes[0] != "Ljava/util/List;") continue
if (constructor.implementation?.findConstString("CompositeConfigurationProvider") != true) continue
val getPropertyMethod = classDef.methods.first { method ->
method.parameterTypes.size > 1 &&
method.returnType == "Ljava/lang/Object;" &&
context.getClass(method.parameterTypes[0])?.interfaces?.contains("Ljava/io/Serializable;") == true &&
context.getClass(method.parameterTypes[1])?.let { it.isEnum() && it.hasStaticConstructorString("BOOLEAN") } == true
}
val getPropertyMethod = classDef.methods.first { method ->
method.parameterTypes.size > 1 &&
method.returnType == "Ljava/lang/Object;" &&
getClass(method.parameterTypes[0])?.interfaces?.contains("Ljava/io/Serializable;") == true &&
getClass(method.parameterTypes[1])?.let { it.isEnum() && it.hasStaticConstructorString("BOOLEAN") } == true
}
val configEnumInterface = context.getClass(getPropertyMethod.parameterTypes[0])!!
val enumType = context.getClass(getPropertyMethod.parameterTypes[1])!!
val configEnumInterface = getClass(getPropertyMethod.parameterTypes[0])!!
val enumType = getClass(getPropertyMethod.parameterTypes[1])!!
val observePropertyMethod = classDef.methods.first {
it.parameterTypes.size > 2 &&
it.parameterTypes[0] == configEnumInterface.type &&
it.parameterTypes[1] == "Ljava/lang/String;" &&
it.parameterTypes[2] == enumType.type
}
val observePropertyMethod = classDef.methods.first {
it.parameterTypes.size > 2 &&
it.parameterTypes[0] == configEnumInterface.type &&
it.parameterTypes[1] == "Ljava/lang/String;" &&
it.parameterTypes[2] == enumType.type
}
val enumGetDefaultValueMethod = configEnumInterface.methods.first { context.getClass(it.returnType)?.interfaces?.contains("Ljava/io/Serializable;") == true }
val defaultValueField = context.getClass(enumGetDefaultValueMethod.returnType)!!.fields.first {
Modifier.isFinal(it.accessFlags) &&
Modifier.isPublic(it.accessFlags) &&
it.type == "Ljava/lang/Object;"
}
val enumGetDefaultValueMethod = configEnumInterface.methods.first { getClass(it.returnType)?.interfaces?.contains("Ljava/io/Serializable;") == true }
val defaultValueField = getClass(enumGetDefaultValueMethod.returnType)!!.fields.first {
Modifier.isFinal(it.accessFlags) &&
Modifier.isPublic(it.accessFlags) &&
it.type == "Ljava/lang/Object;"
}
context.addMapping("CompositeConfigurationProvider",
"class" to classDef.getClassName(),
"observeProperty" to observePropertyMethod.name,
"getProperty" to getPropertyMethod.name,
"enum" to mapOf(
"class" to configEnumInterface.getClassName(),
"getValue" to enumGetDefaultValueMethod.name,
"defaultValueField" to defaultValueField.name
addMapping("CompositeConfigurationProvider",
"class" to classDef.getClassName(),
"observeProperty" to observePropertyMethod.name,
"getProperty" to getPropertyMethod.name,
"enum" to mapOf(
"class" to configEnumInterface.getClassName(),
"getValue" to enumGetDefaultValueMethod.name,
"defaultValueField" to defaultValueField.name
)
)
)
return
return@mapper
}
}
}
}

View File

@ -1,23 +1,24 @@
package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper
import me.rhunk.snapenhance.mapper.MapperContext
import me.rhunk.snapenhance.mapper.ext.getClassName
import me.rhunk.snapenhance.mapper.ext.isAbstract
class DefaultMediaItemMapper : AbstractClassMapper() {
override fun run(context: MapperContext) {
for (clazz in context.classes) {
val superClass = context.getClass(clazz.superclass) ?: continue
init {
mapper {
for (clazz in classes) {
val superClass = getClass(clazz.superclass) ?: continue
if (!superClass.isAbstract() || superClass.interfaces.isEmpty() || superClass.interfaces[0] != "Ljava/lang/Comparable;") continue
if (clazz.methods.none { it.returnType == "Landroid/net/Uri;" }) continue
if (!superClass.isAbstract() || superClass.interfaces.isEmpty() || superClass.interfaces[0] != "Ljava/lang/Comparable;") continue
if (clazz.methods.none { it.returnType == "Landroid/net/Uri;" }) continue
val constructorParameters = clazz.directMethods.firstOrNull { it.name == "<init>" }?.parameterTypes ?: continue
if (constructorParameters.size < 6 || constructorParameters[5] != "J") continue
val constructorParameters = clazz.directMethods.firstOrNull { it.name == "<init>" }?.parameterTypes ?: continue
if (constructorParameters.size < 6 || constructorParameters[5] != "J") continue
context.addMapping("DefaultMediaItem", clazz.getClassName())
return
addMapping("DefaultMediaItem", clazz.getClassName())
return@mapper
}
}
}
}

View File

@ -1,24 +0,0 @@
package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper
import me.rhunk.snapenhance.mapper.MapperContext
import me.rhunk.snapenhance.mapper.ext.getClassName
import me.rhunk.snapenhance.mapper.ext.hasStaticConstructorString
import me.rhunk.snapenhance.mapper.ext.isEnum
class EnumMapper : AbstractClassMapper() {
override fun run(context: MapperContext) {
lateinit var enumQualityLevel : String
for (enumClass in context.classes) {
if (!enumClass.isEnum()) continue
if (enumClass.hasStaticConstructorString("LEVEL_MAX")) {
enumQualityLevel = enumClass.getClassName()
break;
}
}
context.addMapping("EnumQualityLevel", enumQualityLevel)
}
}

View File

@ -1,27 +1,29 @@
package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper
import me.rhunk.snapenhance.mapper.MapperContext
import me.rhunk.snapenhance.mapper.ext.findConstString
import me.rhunk.snapenhance.mapper.ext.getClassName
import me.rhunk.snapenhance.mapper.ext.isEnum
class FriendRelationshipChangerMapper : AbstractClassMapper() {
override fun run(context: MapperContext) {
for (classDef in context.classes) {
classDef.methods.firstOrNull { it.name == "<init>" }?.implementation?.findConstString("FriendRelationshipChangerImpl")?.takeIf { it } ?: continue
val addFriendMethod = classDef.methods.first {
it.parameterTypes.size > 4 &&
context.getClass(it.parameterTypes[1])?.isEnum() == true &&
context.getClass(it.parameterTypes[2])?.isEnum() == true &&
context.getClass(it.parameterTypes[3])?.isEnum() == true &&
it.parameters[4].type == "Ljava/lang/String;"
}
init {
mapper {
for (classDef in classes) {
classDef.methods.firstOrNull { it.name == "<init>" }?.implementation?.findConstString("FriendRelationshipChangerImpl")?.takeIf { it } ?: continue
val addFriendMethod = classDef.methods.first {
it.parameterTypes.size > 4 &&
getClass(it.parameterTypes[1])?.isEnum() == true &&
getClass(it.parameterTypes[2])?.isEnum() == true &&
getClass(it.parameterTypes[3])?.isEnum() == true &&
it.parameters[4].type == "Ljava/lang/String;"
}
context.addMapping("FriendRelationshipChanger",
"class" to classDef.getClassName(),
"addFriendMethod" to addFriendMethod.name
)
addMapping("FriendRelationshipChanger",
"class" to classDef.getClassName(),
"addFriendMethod" to addFriendMethod.name
)
return@mapper
}
}
}
}

View File

@ -1,28 +1,29 @@
package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper
import me.rhunk.snapenhance.mapper.MapperContext
import me.rhunk.snapenhance.mapper.ext.findConstString
import me.rhunk.snapenhance.mapper.ext.getClassName
class FriendsFeedEventDispatcherMapper : AbstractClassMapper() {
override fun run(context: MapperContext) {
for (clazz in context.classes) {
if (clazz.methods.count { it.name == "onClickFeed" || it.name == "onItemLongPress" } != 2) continue
val onItemLongPress = clazz.methods.first { it.name == "onItemLongPress" }
val viewHolderContainerClass = context.getClass(onItemLongPress.parameterTypes[0]) ?: continue
init {
mapper {
for (clazz in classes) {
if (clazz.methods.count { it.name == "onClickFeed" || it.name == "onItemLongPress" } != 2) continue
val onItemLongPress = clazz.methods.first { it.name == "onItemLongPress" }
val viewHolderContainerClass = getClass(onItemLongPress.parameterTypes[0]) ?: continue
val viewModelField = viewHolderContainerClass.fields.firstOrNull { field ->
val typeClass = context.getClass(field.type) ?: return@firstOrNull false
typeClass.methods.firstOrNull {it.name == "toString"}?.implementation?.findConstString("FriendFeedItemViewModel", contains = true) == true
}?.name ?: continue
val viewModelField = viewHolderContainerClass.fields.firstOrNull { field ->
val typeClass = getClass(field.type) ?: return@firstOrNull false
typeClass.methods.firstOrNull {it.name == "toString"}?.implementation?.findConstString("FriendFeedItemViewModel", contains = true) == true
}?.name ?: continue
context.addMapping("FriendsFeedEventDispatcher",
"class" to clazz.getClassName(),
"viewModelField" to viewModelField
)
return
addMapping("FriendsFeedEventDispatcher",
"class" to clazz.getClassName(),
"viewModelField" to viewModelField
)
return@mapper
}
}
}
}

View File

@ -1,25 +1,42 @@
package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper
import me.rhunk.snapenhance.mapper.MapperContext
import me.rhunk.snapenhance.mapper.ext.getClassName
import me.rhunk.snapenhance.mapper.ext.hasStaticConstructorString
import me.rhunk.snapenhance.mapper.ext.isAbstract
import me.rhunk.snapenhance.mapper.ext.isEnum
import org.jf.dexlib2.AccessFlags
class MediaQualityLevelProviderMapper : AbstractClassMapper(EnumMapper::class) {
override fun run(context: MapperContext) {
val mediaQualityLevelClass = context.getStringMapping("EnumQualityLevel") ?: return
class MediaQualityLevelProviderMapper : AbstractClassMapper() {
init {
var enumQualityLevel : String? = null
for (clazz in context.classes) {
if (!clazz.isAbstract()) continue
if (clazz.fields.none { it.accessFlags and AccessFlags.TRANSIENT.value != 0 }) continue
mapper {
for (enumClass in classes) {
if (!enumClass.isEnum()) continue
clazz.methods.firstOrNull { it.returnType == "L$mediaQualityLevelClass;" }?.let {
context.addMapping("MediaQualityLevelProvider",
"class" to clazz.getClassName(),
"method" to it.name
)
return
if (enumClass.hasStaticConstructorString("LEVEL_MAX")) {
enumQualityLevel = enumClass.getClassName()
break;
}
}
addMapping("EnumQualityLevel", enumQualityLevel ?: return@mapper)
}
mapper {
if (enumQualityLevel == null) return@mapper
for (clazz in classes) {
if (!clazz.isAbstract()) continue
if (clazz.fields.none { it.accessFlags and AccessFlags.TRANSIENT.value != 0 }) continue
clazz.methods.firstOrNull { it.returnType == "L$enumQualityLevel;" }?.let {
addMapping("MediaQualityLevelProvider",
"class" to clazz.getClassName(),
"method" to it.name
)
return@mapper
}
}
}
}

View File

@ -1,7 +1,6 @@
package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper
import me.rhunk.snapenhance.mapper.MapperContext
import me.rhunk.snapenhance.mapper.ext.getClassName
import me.rhunk.snapenhance.mapper.ext.hasConstructorString
import me.rhunk.snapenhance.mapper.ext.hasStaticConstructorString
@ -9,45 +8,47 @@ import me.rhunk.snapenhance.mapper.ext.isAbstract
import me.rhunk.snapenhance.mapper.ext.isEnum
class OperaPageViewControllerMapper : AbstractClassMapper() {
override fun run(context: MapperContext) {
for (clazz in context.classes) {
if (!clazz.isAbstract()) continue
if (!clazz.hasConstructorString("OperaPageViewController") || !clazz.hasStaticConstructorString("ad_product_type")) {
continue
}
val viewStateField = clazz.fields.first { field ->
val fieldClass = context.getClass(field.type) ?: return@first false
fieldClass.isEnum() && fieldClass.hasStaticConstructorString("FULLY_DISPLAYED")
}
val layerListField = clazz.fields.first { it.type == "Ljava/util/ArrayList;" }
val onDisplayStateChange = clazz.methods.first {
if (it.returnType != "V" || it.parameterTypes.size != 1) return@first false
val firstParameterType = context.getClass(it.parameterTypes[0]) ?: return@first false
//check if the class contains a field with the enumViewStateClass type
firstParameterType.fields.any { field ->
field.type == viewStateField.type
init {
mapper {
for (clazz in classes) {
if (!clazz.isAbstract()) continue
if (!clazz.hasConstructorString("OperaPageViewController") || !clazz.hasStaticConstructorString("ad_product_type")) {
continue
}
val viewStateField = clazz.fields.first { field ->
val fieldClass = getClass(field.type) ?: return@first false
fieldClass.isEnum() && fieldClass.hasStaticConstructorString("FULLY_DISPLAYED")
}
val layerListField = clazz.fields.first { it.type == "Ljava/util/ArrayList;" }
val onDisplayStateChange = clazz.methods.first {
if (it.returnType != "V" || it.parameterTypes.size != 1) return@first false
val firstParameterType = getClass(it.parameterTypes[0]) ?: return@first false
//check if the class contains a field with the enumViewStateClass type
firstParameterType.fields.any { field ->
field.type == viewStateField.type
}
}
val onDisplayStateChangeGesture = clazz.methods.first {
if (it.returnType != "V" || it.parameterTypes.size != 2) return@first false
val firstParameterType = getClass(it.parameterTypes[0]) ?: return@first false
val secondParameterType = getClass(it.parameterTypes[1]) ?: return@first false
firstParameterType.isEnum() && secondParameterType.isEnum()
}
addMapping("OperaPageViewController",
"class" to clazz.getClassName(),
"viewStateField" to viewStateField.name,
"layerListField" to layerListField.name,
"onDisplayStateChange" to onDisplayStateChange.name,
"onDisplayStateChangeGesture" to onDisplayStateChangeGesture.name
)
return@mapper
}
val onDisplayStateChangeGesture = clazz.methods.first {
if (it.returnType != "V" || it.parameterTypes.size != 2) return@first false
val firstParameterType = context.getClass(it.parameterTypes[0]) ?: return@first false
val secondParameterType = context.getClass(it.parameterTypes[1]) ?: return@first false
firstParameterType.isEnum() && secondParameterType.isEnum()
}
context.addMapping("OperaPageViewController",
"class" to clazz.getClassName(),
"viewStateField" to viewStateField.name,
"layerListField" to layerListField.name,
"onDisplayStateChange" to onDisplayStateChange.name,
"onDisplayStateChangeGesture" to onDisplayStateChangeGesture.name
)
return
}
}
}

View File

@ -1,25 +1,26 @@
package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper
import me.rhunk.snapenhance.mapper.MapperContext
import me.rhunk.snapenhance.mapper.ext.findConstString
import me.rhunk.snapenhance.mapper.ext.getClassName
import me.rhunk.snapenhance.mapper.ext.getStaticConstructor
import me.rhunk.snapenhance.mapper.ext.isEnum
class PlatformAnalyticsCreatorMapper : AbstractClassMapper() {
override fun run(context: MapperContext) {
for (clazz in context.classes) {
val firstConstructor = clazz.directMethods.firstOrNull { it.name == "<init>" } ?: continue
// 47 is the number of parameters of the constructor
// it may change in future versions
if (firstConstructor.parameters.size != 47) continue
val firstParameterClass = context.getClass(firstConstructor.parameterTypes[0]) ?: continue
if (!firstParameterClass.isEnum()) continue
if (firstParameterClass.getStaticConstructor()?.implementation?.findConstString("IN_APP_NOTIFICATION") != true) continue
init {
mapper {
for (clazz in classes) {
val firstConstructor = clazz.directMethods.firstOrNull { it.name == "<init>" } ?: continue
// 47 is the number of parameters of the constructor
// it may change in future versions
if (firstConstructor.parameters.size != 47) continue
val firstParameterClass = getClass(firstConstructor.parameterTypes[0]) ?: continue
if (!firstParameterClass.isEnum()) continue
if (firstParameterClass.getStaticConstructor()?.implementation?.findConstString("IN_APP_NOTIFICATION") != true) continue
context.addMapping("PlatformAnalyticsCreator", clazz.getClassName())
return
addMapping("PlatformAnalyticsCreator", clazz.getClassName())
return@mapper
}
}
}
}

View File

@ -1,28 +1,29 @@
package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper
import me.rhunk.snapenhance.mapper.MapperContext
import me.rhunk.snapenhance.mapper.ext.findConstString
import me.rhunk.snapenhance.mapper.ext.getClassName
class PlusSubscriptionMapper : AbstractClassMapper(){
override fun run(context: MapperContext) {
for (clazz in context.classes) {
if (clazz.directMethods.filter { it.name == "<init>" }.none {
it.parameters.size == 4 &&
it.parameterTypes[0] == "I" &&
it.parameterTypes[1] == "I" &&
it.parameterTypes[2] == "J" &&
it.parameterTypes[3] == "J"
}) continue
init {
mapper {
for (clazz in classes) {
if (clazz.directMethods.filter { it.name == "<init>" }.none {
it.parameters.size == 4 &&
it.parameterTypes[0] == "I" &&
it.parameterTypes[1] == "I" &&
it.parameterTypes[2] == "J" &&
it.parameterTypes[3] == "J"
}) continue
val isPlusSubscriptionInfoClass = clazz.virtualMethods.firstOrNull { it.name == "toString" }?.implementation?.let {
it.findConstString("SubscriptionInfo", contains = true) && it.findConstString("expirationTimeMillis", contains = true)
}
val isPlusSubscriptionInfoClass = clazz.virtualMethods.firstOrNull { it.name == "toString" }?.implementation?.let {
it.findConstString("SubscriptionInfo", contains = true) && it.findConstString("expirationTimeMillis", contains = true)
}
if (isPlusSubscriptionInfoClass == true) {
context.addMapping("SubscriptionInfoClass", clazz.getClassName())
return
if (isPlusSubscriptionInfoClass == true) {
addMapping("SubscriptionInfoClass", clazz.getClassName())
return@mapper
}
}
}
}

View File

@ -1,22 +1,23 @@
package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper
import me.rhunk.snapenhance.mapper.MapperContext
import me.rhunk.snapenhance.mapper.ext.findConstString
import me.rhunk.snapenhance.mapper.ext.getClassName
import me.rhunk.snapenhance.mapper.ext.getStaticConstructor
import me.rhunk.snapenhance.mapper.ext.isEnum
class ScCameraSettingsMapper : AbstractClassMapper() {
override fun run(context: MapperContext) {
for (clazz in context.classes) {
val firstConstructor = clazz.directMethods.firstOrNull { it.name == "<init>" } ?: continue
if (firstConstructor.parameterTypes.size < 27) continue
val firstParameter = context.getClass(firstConstructor.parameterTypes[0]) ?: continue
if (!firstParameter.isEnum() || firstParameter.getStaticConstructor()?.implementation?.findConstString("CONTINUOUS_PICTURE") != true) continue
init {
mapper {
for (clazz in classes) {
val firstConstructor = clazz.directMethods.firstOrNull { it.name == "<init>" } ?: continue
if (firstConstructor.parameterTypes.size < 27) continue
val firstParameter = getClass(firstConstructor.parameterTypes[0]) ?: continue
if (!firstParameter.isEnum() || firstParameter.getStaticConstructor()?.implementation?.findConstString("CONTINUOUS_PICTURE") != true) continue
context.addMapping("ScCameraSettings", clazz.getClassName())
return
addMapping("ScCameraSettings", clazz.getClassName())
return@mapper
}
}
}
}

View File

@ -1,25 +1,26 @@
package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper
import me.rhunk.snapenhance.mapper.MapperContext
import me.rhunk.snapenhance.mapper.ext.findConstString
import me.rhunk.snapenhance.mapper.ext.getClassName
class ScoreUpdateMapper : AbstractClassMapper() {
override fun run(context: MapperContext) {
for (classDef in context.classes) {
classDef.methods.firstOrNull {
it.name == "<init>" &&
it.parameterTypes.size > 4 &&
it.parameterTypes[1] == "Ljava/lang/Long;" &&
it.parameterTypes[3] == "Ljava/util/Collection;"
} ?: continue
if (classDef.methods.firstOrNull {
it.name == "toString"
}?.implementation?.findConstString("Friend.sq:selectFriendUserScoresNeedToUpdate") != true) continue
init {
mapper {
for (classDef in classes) {
classDef.methods.firstOrNull {
it.name == "<init>" &&
it.parameterTypes.size > 4 &&
it.parameterTypes[1] == "Ljava/lang/Long;" &&
it.parameterTypes[3] == "Ljava/util/Collection;"
} ?: continue
if (classDef.methods.firstOrNull {
it.name == "toString"
}?.implementation?.findConstString("Friend.sq:selectFriendUserScoresNeedToUpdate") != true) continue
context.addMapping("ScoreUpdate", classDef.getClassName())
return
addMapping("ScoreUpdate", classDef.getClassName())
return@mapper
}
}
}
}

View File

@ -1,21 +1,22 @@
package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper
import me.rhunk.snapenhance.mapper.MapperContext
import me.rhunk.snapenhance.mapper.ext.findConstString
import me.rhunk.snapenhance.mapper.ext.getClassName
class StoryBoostStateMapper : AbstractClassMapper() {
override fun run(context: MapperContext) {
for (clazz in context.classes) {
val firstConstructor = clazz.directMethods.firstOrNull { it.name == "<init>" } ?: continue
if (firstConstructor.parameters.size != 3) continue
if (firstConstructor.parameterTypes[1] != "J" || firstConstructor.parameterTypes[2] != "J") continue
init {
mapper {
for (clazz in classes) {
val firstConstructor = clazz.directMethods.firstOrNull { it.name == "<init>" } ?: continue
if (firstConstructor.parameters.size != 3) continue
if (firstConstructor.parameterTypes[1] != "J" || firstConstructor.parameterTypes[2] != "J") continue
if (clazz.methods.firstOrNull { it.name == "toString" }?.implementation?.findConstString("StoryBoostState", contains = true) != true) continue
if (clazz.methods.firstOrNull { it.name == "toString" }?.implementation?.findConstString("StoryBoostState", contains = true) != true) continue
context.addMapping("StoryBoostStateClass", clazz.getClassName())
return
addMapping("StoryBoostStateClass", clazz.getClassName())
return@mapper
}
}
}
}

View File

@ -1,37 +1,39 @@
package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper
import me.rhunk.snapenhance.mapper.MapperContext
import me.rhunk.snapenhance.mapper.ext.getClassName
import me.rhunk.snapenhance.mapper.ext.isAbstract
import me.rhunk.snapenhance.mapper.ext.isInterface
import java.lang.reflect.Modifier
class ViewBinderMapper : AbstractClassMapper() {
override fun run(context: MapperContext) {
for (clazz in context.classes) {
if (!clazz.isAbstract() || clazz.isInterface()) continue
init {
mapper {
for (clazz in classes) {
if (!clazz.isAbstract() || clazz.isInterface()) continue
val getViewMethod = clazz.methods.firstOrNull { it.returnType == "Landroid/view/View;" && it.parameterTypes.size == 0 } ?: continue
val getViewMethod = clazz.methods.firstOrNull { it.returnType == "Landroid/view/View;" && it.parameterTypes.size == 0 } ?: continue
// update view
clazz.methods.filter {
Modifier.isAbstract(it.accessFlags) && it.parameterTypes.size == 1 && it.parameterTypes[0] == "Landroid/view/View;" && it.returnType == "V"
}.also {
if (it.size != 1) return@also
}.firstOrNull() ?: continue
// update view
clazz.methods.filter {
Modifier.isAbstract(it.accessFlags) && it.parameterTypes.size == 1 && it.parameterTypes[0] == "Landroid/view/View;" && it.returnType == "V"
}.also {
if (it.size != 1) return@also
}.firstOrNull() ?: continue
val bindMethod = clazz.methods.filter {
Modifier.isAbstract(it.accessFlags) && it.parameterTypes.size == 2 && it.parameterTypes[0] == it.parameterTypes[1] && it.returnType == "V"
}.also {
if (it.size != 1) return@also
}.firstOrNull() ?: continue
val bindMethod = clazz.methods.filter {
Modifier.isAbstract(it.accessFlags) && it.parameterTypes.size == 2 && it.parameterTypes[0] == it.parameterTypes[1] && it.returnType == "V"
}.also {
if (it.size != 1) return@also
}.firstOrNull() ?: continue
context.addMapping("ViewBinder",
"class" to clazz.getClassName(),
"bindMethod" to bindMethod.name,
"getViewMethod" to getViewMethod.name
)
addMapping("ViewBinder",
"class" to clazz.getClassName(),
"bindMethod" to bindMethod.name,
"getViewMethod" to getViewMethod.name
)
return@mapper
}
}
}
}

View File

@ -15,7 +15,6 @@ class TestMappings {
CallbackMapper::class,
DefaultMediaItemMapper::class,
MediaQualityLevelProviderMapper::class,
EnumMapper::class,
OperaPageViewControllerMapper::class,
PlatformAnalyticsCreatorMapper::class,
PlusSubscriptionMapper::class,
@ -25,7 +24,7 @@ class TestMappings {
CompositeConfigurationProviderMapper::class,
ScoreUpdateMapper::class,
FriendRelationshipChangerMapper::class,
ViewBinderMapper::class
ViewBinderMapper::class,
)
val gson = GsonBuilder().setPrettyPrinting().create()