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

@ -21,7 +21,6 @@ class MappingsWrapper : FileLoaderWrapper(BridgeFileType.MAPPINGS, "{}".toByteAr
CallbackMapper::class, CallbackMapper::class,
DefaultMediaItemMapper::class, DefaultMediaItemMapper::class,
MediaQualityLevelProviderMapper::class, MediaQualityLevelProviderMapper::class,
EnumMapper::class,
OperaPageViewControllerMapper::class, OperaPageViewControllerMapper::class,
PlatformAnalyticsCreatorMapper::class, PlatformAnalyticsCreatorMapper::class,
PlusSubscriptionMapper::class, PlusSubscriptionMapper::class,

View File

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

View File

@ -56,30 +56,9 @@ class Mapper(
runBlocking { runBlocking {
withContext(Dispatchers.IO) { 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 -> mappers.forEach { mapper ->
if (mapper.dependsOn.isNotEmpty()) return@forEach
launch { launch {
mapper.run(context) mapper.run(context)
onJobFinished(mapper)
} }
} }
} }

View File

@ -1,34 +1,35 @@
package me.rhunk.snapenhance.mapper.impl package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper 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.getClassName
import me.rhunk.snapenhance.mapper.ext.getStaticConstructor import me.rhunk.snapenhance.mapper.ext.getStaticConstructor
import me.rhunk.snapenhance.mapper.ext.isFinal import me.rhunk.snapenhance.mapper.ext.isFinal
import org.jf.dexlib2.iface.instruction.formats.ArrayPayload import org.jf.dexlib2.iface.instruction.formats.ArrayPayload
class BCryptClassMapper : AbstractClassMapper() { class BCryptClassMapper : AbstractClassMapper() {
override fun run(context: MapperContext) { init {
for (clazz in context.classes) { mapper {
if (!clazz.isFinal()) continue for (clazz in classes) {
if (!clazz.isFinal()) continue
val isBcryptClass = clazz.getStaticConstructor()?.let { constructor -> val isBcryptClass = clazz.getStaticConstructor()?.let { constructor ->
constructor.implementation?.instructions?.filterIsInstance<ArrayPayload>()?.any { it.arrayElements.size == 18 && it.arrayElements[0] == 608135816 } 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;"
} }
context.addMapping("BCrypt", if (isBcryptClass == true) {
"class" to clazz.getClassName(), val hashMethod = clazz.methods.first {
"hashMethod" to hashMethod.name it.parameterTypes.size == 2 &&
) it.parameterTypes[0] == "Ljava/lang/String;" &&
return 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 package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper 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.getClassName
import me.rhunk.snapenhance.mapper.ext.getSuperClassName import me.rhunk.snapenhance.mapper.ext.getSuperClassName
import me.rhunk.snapenhance.mapper.ext.isFinal import me.rhunk.snapenhance.mapper.ext.isFinal
class CallbackMapper : AbstractClassMapper() { class CallbackMapper : AbstractClassMapper() {
override fun run(context: MapperContext) { init {
val callbackClasses = context.classes.filter { clazz -> mapper {
if (clazz.superclass == null) return@filter false val callbackClasses = classes.filter { clazz ->
if (clazz.superclass == null) return@filter false
val superclassName = clazz.getSuperClassName()!! val superclassName = clazz.getSuperClassName()!!
if ((!superclassName.endsWith("Callback") && !superclassName.endsWith("Delegate")) if ((!superclassName.endsWith("Callback") && !superclassName.endsWith("Delegate"))
|| superclassName.endsWith("\$Callback")) return@filter false || 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 val superClass = getClass(clazz.superclass) ?: return@filter false
!superClass.isFinal() !superClass.isFinal()
}.map { }.map {
it.getSuperClassName()!!.substringAfterLast("/") to it.getClassName() 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 package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper 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.findConstString
import me.rhunk.snapenhance.mapper.ext.getClassName import me.rhunk.snapenhance.mapper.ext.getClassName
import me.rhunk.snapenhance.mapper.ext.hasStaticConstructorString import me.rhunk.snapenhance.mapper.ext.hasStaticConstructorString
@ -9,47 +8,49 @@ import me.rhunk.snapenhance.mapper.ext.isEnum
import java.lang.reflect.Modifier import java.lang.reflect.Modifier
class CompositeConfigurationProviderMapper : AbstractClassMapper() { class CompositeConfigurationProviderMapper : AbstractClassMapper() {
override fun run(context: MapperContext) { init {
for (classDef in context.classes) { mapper {
val constructor = classDef.methods.firstOrNull { it.name == "<init>" } ?: continue for (classDef in classes) {
if (constructor.parameterTypes.size == 0 || constructor.parameterTypes[0] != "Ljava/util/List;") continue val constructor = classDef.methods.firstOrNull { it.name == "<init>" } ?: continue
if (constructor.implementation?.findConstString("CompositeConfigurationProvider") != true) 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 -> val getPropertyMethod = classDef.methods.first { method ->
method.parameterTypes.size > 1 && method.parameterTypes.size > 1 &&
method.returnType == "Ljava/lang/Object;" && method.returnType == "Ljava/lang/Object;" &&
context.getClass(method.parameterTypes[0])?.interfaces?.contains("Ljava/io/Serializable;") == true && getClass(method.parameterTypes[0])?.interfaces?.contains("Ljava/io/Serializable;") == true &&
context.getClass(method.parameterTypes[1])?.let { it.isEnum() && it.hasStaticConstructorString("BOOLEAN") } == true getClass(method.parameterTypes[1])?.let { it.isEnum() && it.hasStaticConstructorString("BOOLEAN") } == true
} }
val configEnumInterface = context.getClass(getPropertyMethod.parameterTypes[0])!! val configEnumInterface = getClass(getPropertyMethod.parameterTypes[0])!!
val enumType = context.getClass(getPropertyMethod.parameterTypes[1])!! val enumType = getClass(getPropertyMethod.parameterTypes[1])!!
val observePropertyMethod = classDef.methods.first { val observePropertyMethod = classDef.methods.first {
it.parameterTypes.size > 2 && it.parameterTypes.size > 2 &&
it.parameterTypes[0] == configEnumInterface.type && it.parameterTypes[0] == configEnumInterface.type &&
it.parameterTypes[1] == "Ljava/lang/String;" && it.parameterTypes[1] == "Ljava/lang/String;" &&
it.parameterTypes[2] == enumType.type it.parameterTypes[2] == enumType.type
} }
val enumGetDefaultValueMethod = configEnumInterface.methods.first { context.getClass(it.returnType)?.interfaces?.contains("Ljava/io/Serializable;") == true } val enumGetDefaultValueMethod = configEnumInterface.methods.first { getClass(it.returnType)?.interfaces?.contains("Ljava/io/Serializable;") == true }
val defaultValueField = context.getClass(enumGetDefaultValueMethod.returnType)!!.fields.first { val defaultValueField = getClass(enumGetDefaultValueMethod.returnType)!!.fields.first {
Modifier.isFinal(it.accessFlags) && Modifier.isFinal(it.accessFlags) &&
Modifier.isPublic(it.accessFlags) && Modifier.isPublic(it.accessFlags) &&
it.type == "Ljava/lang/Object;" it.type == "Ljava/lang/Object;"
} }
context.addMapping("CompositeConfigurationProvider", addMapping("CompositeConfigurationProvider",
"class" to classDef.getClassName(), "class" to classDef.getClassName(),
"observeProperty" to observePropertyMethod.name, "observeProperty" to observePropertyMethod.name,
"getProperty" to getPropertyMethod.name, "getProperty" to getPropertyMethod.name,
"enum" to mapOf( "enum" to mapOf(
"class" to configEnumInterface.getClassName(), "class" to configEnumInterface.getClassName(),
"getValue" to enumGetDefaultValueMethod.name, "getValue" to enumGetDefaultValueMethod.name,
"defaultValueField" to defaultValueField.name "defaultValueField" to defaultValueField.name
)
) )
) return@mapper
return }
} }
} }
} }

View File

@ -1,23 +1,24 @@
package me.rhunk.snapenhance.mapper.impl package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper 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.getClassName
import me.rhunk.snapenhance.mapper.ext.isAbstract import me.rhunk.snapenhance.mapper.ext.isAbstract
class DefaultMediaItemMapper : AbstractClassMapper() { class DefaultMediaItemMapper : AbstractClassMapper() {
override fun run(context: MapperContext) { init {
for (clazz in context.classes) { mapper {
val superClass = context.getClass(clazz.superclass) ?: continue for (clazz in classes) {
val superClass = getClass(clazz.superclass) ?: continue
if (!superClass.isAbstract() || superClass.interfaces.isEmpty() || superClass.interfaces[0] != "Ljava/lang/Comparable;") 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 (clazz.methods.none { it.returnType == "Landroid/net/Uri;" }) continue
val constructorParameters = clazz.directMethods.firstOrNull { it.name == "<init>" }?.parameterTypes ?: continue val constructorParameters = clazz.directMethods.firstOrNull { it.name == "<init>" }?.parameterTypes ?: continue
if (constructorParameters.size < 6 || constructorParameters[5] != "J") continue if (constructorParameters.size < 6 || constructorParameters[5] != "J") continue
context.addMapping("DefaultMediaItem", clazz.getClassName()) addMapping("DefaultMediaItem", clazz.getClassName())
return 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 package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper 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.findConstString
import me.rhunk.snapenhance.mapper.ext.getClassName import me.rhunk.snapenhance.mapper.ext.getClassName
import me.rhunk.snapenhance.mapper.ext.isEnum import me.rhunk.snapenhance.mapper.ext.isEnum
class FriendRelationshipChangerMapper : AbstractClassMapper() { class FriendRelationshipChangerMapper : AbstractClassMapper() {
override fun run(context: MapperContext) { init {
for (classDef in context.classes) { mapper {
classDef.methods.firstOrNull { it.name == "<init>" }?.implementation?.findConstString("FriendRelationshipChangerImpl")?.takeIf { it } ?: continue for (classDef in classes) {
val addFriendMethod = classDef.methods.first { classDef.methods.firstOrNull { it.name == "<init>" }?.implementation?.findConstString("FriendRelationshipChangerImpl")?.takeIf { it } ?: continue
it.parameterTypes.size > 4 && val addFriendMethod = classDef.methods.first {
context.getClass(it.parameterTypes[1])?.isEnum() == true && it.parameterTypes.size > 4 &&
context.getClass(it.parameterTypes[2])?.isEnum() == true && getClass(it.parameterTypes[1])?.isEnum() == true &&
context.getClass(it.parameterTypes[3])?.isEnum() == true && getClass(it.parameterTypes[2])?.isEnum() == true &&
it.parameters[4].type == "Ljava/lang/String;" getClass(it.parameterTypes[3])?.isEnum() == true &&
} it.parameters[4].type == "Ljava/lang/String;"
}
context.addMapping("FriendRelationshipChanger", addMapping("FriendRelationshipChanger",
"class" to classDef.getClassName(), "class" to classDef.getClassName(),
"addFriendMethod" to addFriendMethod.name "addFriendMethod" to addFriendMethod.name
) )
return@mapper
}
} }
} }
} }

View File

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

View File

@ -1,25 +1,42 @@
package me.rhunk.snapenhance.mapper.impl package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper 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.getClassName
import me.rhunk.snapenhance.mapper.ext.hasStaticConstructorString
import me.rhunk.snapenhance.mapper.ext.isAbstract import me.rhunk.snapenhance.mapper.ext.isAbstract
import me.rhunk.snapenhance.mapper.ext.isEnum
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
class MediaQualityLevelProviderMapper : AbstractClassMapper(EnumMapper::class) { class MediaQualityLevelProviderMapper : AbstractClassMapper() {
override fun run(context: MapperContext) { init {
val mediaQualityLevelClass = context.getStringMapping("EnumQualityLevel") ?: return var enumQualityLevel : String? = null
for (clazz in context.classes) { mapper {
if (!clazz.isAbstract()) continue for (enumClass in classes) {
if (clazz.fields.none { it.accessFlags and AccessFlags.TRANSIENT.value != 0 }) continue if (!enumClass.isEnum()) continue
clazz.methods.firstOrNull { it.returnType == "L$mediaQualityLevelClass;" }?.let { if (enumClass.hasStaticConstructorString("LEVEL_MAX")) {
context.addMapping("MediaQualityLevelProvider", enumQualityLevel = enumClass.getClassName()
"class" to clazz.getClassName(), break;
"method" to it.name }
) }
return 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 package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper 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.getClassName
import me.rhunk.snapenhance.mapper.ext.hasConstructorString import me.rhunk.snapenhance.mapper.ext.hasConstructorString
import me.rhunk.snapenhance.mapper.ext.hasStaticConstructorString 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 import me.rhunk.snapenhance.mapper.ext.isEnum
class OperaPageViewControllerMapper : AbstractClassMapper() { class OperaPageViewControllerMapper : AbstractClassMapper() {
override fun run(context: MapperContext) { init {
for (clazz in context.classes) { mapper {
if (!clazz.isAbstract()) continue for (clazz in classes) {
if (!clazz.hasConstructorString("OperaPageViewController") || !clazz.hasStaticConstructorString("ad_product_type")) { if (!clazz.isAbstract()) continue
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
} }
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 package me.rhunk.snapenhance.mapper.impl
import me.rhunk.snapenhance.mapper.AbstractClassMapper 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.findConstString
import me.rhunk.snapenhance.mapper.ext.getClassName import me.rhunk.snapenhance.mapper.ext.getClassName
import me.rhunk.snapenhance.mapper.ext.getStaticConstructor import me.rhunk.snapenhance.mapper.ext.getStaticConstructor
import me.rhunk.snapenhance.mapper.ext.isEnum import me.rhunk.snapenhance.mapper.ext.isEnum
class PlatformAnalyticsCreatorMapper : AbstractClassMapper() { class PlatformAnalyticsCreatorMapper : AbstractClassMapper() {
override fun run(context: MapperContext) { init {
for (clazz in context.classes) { mapper {
val firstConstructor = clazz.directMethods.firstOrNull { it.name == "<init>" } ?: continue for (clazz in classes) {
// 47 is the number of parameters of the constructor val firstConstructor = clazz.directMethods.firstOrNull { it.name == "<init>" } ?: continue
// it may change in future versions // 47 is the number of parameters of the constructor
if (firstConstructor.parameters.size != 47) continue // it may change in future versions
val firstParameterClass = context.getClass(firstConstructor.parameterTypes[0]) ?: continue if (firstConstructor.parameters.size != 47) continue
if (!firstParameterClass.isEnum()) continue val firstParameterClass = getClass(firstConstructor.parameterTypes[0]) ?: continue
if (firstParameterClass.getStaticConstructor()?.implementation?.findConstString("IN_APP_NOTIFICATION") != true) continue if (!firstParameterClass.isEnum()) continue
if (firstParameterClass.getStaticConstructor()?.implementation?.findConstString("IN_APP_NOTIFICATION") != true) continue
context.addMapping("PlatformAnalyticsCreator", clazz.getClassName()) addMapping("PlatformAnalyticsCreator", clazz.getClassName())
return return@mapper
}
} }
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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