Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
main.com.xml.guard.model.MappingParser.kt Maven / Gradle / Ivy
package com.xml.guard.model
import com.xml.guard.entensions.GuardExtension
import com.xml.guard.utils.inClassNameBlackList
import com.xml.guard.utils.inPackageNameBlackList
import com.xml.guard.utils.to26Long
import org.gradle.api.Project
import java.io.File
import java.util.regex.Pattern
/**
* User: ljx
* Date: 2022/3/25
* Time: 11:15
*/
object MappingParser {
private val mappingPattern: Pattern by lazy { Pattern.compile("\\s*(.*)->(.*)") }
private val uppercasePattern: Pattern by lazy { Pattern.compile("^[A-Z]+$") }
private val lowerPattern: Pattern by lazy { Pattern.compile("^[a-z]+$") }
internal const val MAPPING_XML_CLASS = "guard-xml-class-mapping.txt"
internal const val MAPPING_RES = "guard-res-mapping.txt"
internal const val MAPPING_STRING_FOR = "guard-string-fog-mapping.txt"
internal const val MAPPING_DECLARATION = "guard-declaration-mapping.txt"
internal const val MAPPING_CUSTOM_STRING = "guard-custom-string-mapping.txt"
internal const val DIR_MAPPING = "dir mapping:"
internal const val CLASS_MAPPING = "class mapping:"
internal const val RES_MAPPING = "res mapping:"
internal const val LAYOUT_MAPPING = "layout mapping:"
internal const val VALUES_MAPPING = "values mapping:"
internal const val STATIC_FIELD_MAPPING = "static field mapping:"
internal const val NON_STATIC_FIELD_MAPPING = "non static field mapping:"
internal const val METHOD_NAME_MAPPING = "method name mapping:"
internal const val METHOD_PARAMETER_MAPPING = "method parameter mapping:"
internal const val ENUM_CONSTANT_MAPPING = "enum constant mapping:"
internal const val STRING_FOG_KEY = "stringFogKey"
internal const val STRING_FOG_METHOD = "stringFogMethodName"
internal const val STRING_FOG_CLASS_NAME = "stringFogClassName"
internal const val STRING_FOG_DIR_NAME = "stringFogDirName"
fun parseCustomString(
project: Project,
guardExtension: GuardExtension,
mappingFile: File,
isComparison: Boolean = false
): CustomStringMapping {
var obfuscateIndex = -1L
if (isComparison) {
obfuscateIndex = compareObfuscateIndex(project, guardExtension, mappingFile)
}
val mapping = CustomStringMapping(guardExtension)
if (!mappingFile.exists()) {
return mapping.apply { this.obfuscateIndex = obfuscateIndex }
}
parse(mappingFile) { _, _, key, value ->
val minimumValue = value.let {
// 若字符串包含 _ 连接符,则取字符串首个 _ 前的字符(参与混淆名称的生成)
(it.split("_").firstOrNull() ?: it).to26Long()
}
obfuscateIndex = obfuscateIndex.coerceAtLeast(minimumValue)
mapping.customStringMapping[key] = value
}
mapping.obfuscateIndex = mapping.obfuscateIndex.coerceAtLeast(obfuscateIndex)
return mapping
}
fun parseDeclaration(
project: Project,
guardExtension: GuardExtension,
mappingFile: File,
isComparison: Boolean = false
): DeclarationMapping {
var obfuscateIndex = -1L
if (isComparison) {
obfuscateIndex = compareObfuscateIndex(project, guardExtension, mappingFile)
}
val mapping = DeclarationMapping(guardExtension)
if (!mappingFile.exists()) {
return mapping.apply { this.obfuscateIndex = obfuscateIndex }
}
parse(mappingFile) { _, mappingType, key, value ->
// 已混淆
if (mapping.isObfuscated(key)) {
return@parse
}
// 白名单
if (mapping.inWhiteList(key)) {
return@parse
}
val minimumValue = value.let {
// 若字符串包含 _ 连接符,则取字符串首个 _ 前的字符(参与混淆名称的生成)
(it.split("_").firstOrNull() ?: it).to26Long()
}
obfuscateIndex = obfuscateIndex.coerceAtLeast(minimumValue)
when (mappingType) {
STATIC_FIELD_MAPPING -> {
mapping.allMappingMap[key] = value
mapping.staticFieldMapping[key] = value
}
NON_STATIC_FIELD_MAPPING -> {
mapping.allMappingMap[key] = value
mapping.nonStaticFieldMapping[key] = value
}
METHOD_NAME_MAPPING -> {
mapping.allMappingMap[key] = value
mapping.methodNameMapping[key] = value
}
METHOD_PARAMETER_MAPPING -> {
mapping.allMappingMap[key] = value
mapping.methodParameterMapping[key] = value
}
ENUM_CONSTANT_MAPPING -> {
mapping.allMappingMap[key] = value
mapping.enumConstantMapping[key] = value
}
}
}
mapping.obfuscateIndex = mapping.obfuscateIndex.coerceAtLeast(obfuscateIndex)
return mapping
}
fun parseStringFog(
project: Project,
guardExtension: GuardExtension,
mappingFile: File,
isComparison: Boolean = false
): StringFogMapping {
var obfuscateIndex = -1L
if (isComparison) {
obfuscateIndex = compareObfuscateIndex(project, guardExtension, mappingFile)
}
val mapping = StringFogMapping(guardExtension)
if (!mappingFile.exists()) {
return mapping.apply { this.obfuscateIndex = obfuscateIndex }
}
parse(mappingFile) { line, _, key, value ->
when (key) {
STRING_FOG_KEY -> {
if (value.length != 8) {
throw IllegalArgumentException("`${line.trim()}` is illegal, $value is wrong")
}
mapping.stringFogKey = value
}
STRING_FOG_METHOD -> {
mapping.stringFogMethodName = value
val minimumValue = value.to26Long()
obfuscateIndex = obfuscateIndex.coerceAtLeast(minimumValue)
}
STRING_FOG_CLASS_NAME -> {
mapping.stringFogClassName = value
val minimumValue = value.to26Long()
obfuscateIndex = obfuscateIndex.coerceAtLeast(minimumValue)
}
STRING_FOG_DIR_NAME -> {
mapping.stringFogDirName = value
val minimumValue = value.to26Long()
obfuscateIndex = obfuscateIndex.coerceAtLeast(minimumValue)
}
}
}
mapping.obfuscateIndex = mapping.obfuscateIndex.coerceAtLeast(obfuscateIndex)
return mapping
}
fun parseRes(
project: Project,
guardExtension: GuardExtension,
mappingFile: File,
isComparison: Boolean = false
): ResMapping {
var obfuscateIndex = -1L
if (isComparison) {
obfuscateIndex = compareObfuscateIndex(project, guardExtension, mappingFile)
}
val mapping = ResMapping(guardExtension)
if (!mappingFile.exists()) {
return mapping.apply { this.obfuscateIndex = obfuscateIndex }
}
parse(mappingFile) { line, mappingType, rawName, value ->
if (value.inPackageNameBlackList()) {
throw IllegalArgumentException("`${line.trim()}` is illegal, $value is a keyword")
}
val minimumValue = value.let {
// 若字符串包含 _ 连接符,则取字符串首个 _ 前的字符(参与混淆名称的生成)
(it.split("_").firstOrNull() ?: it).to26Long()
}
obfuscateIndex = obfuscateIndex.coerceAtLeast(minimumValue)
when (mappingType) {
LAYOUT_MAPPING -> {
mapping.layoutMapping[rawName] = value
}
RES_MAPPING -> {
mapping.resMapping[rawName] = value
}
VALUES_MAPPING -> {
mapping.valuesMapping[rawName] = value
}
else -> {}
}
}
mapping.obfuscateIndex = mapping.obfuscateIndex.coerceAtLeast(obfuscateIndex)
return mapping
}
fun parseXmlClass(
project: Project,
guardExtension: GuardExtension,
mappingFile: File,
isComparison: Boolean = false
): XmlClassMapping {
var obfuscateIndex = -1L
if (isComparison) {
obfuscateIndex = compareObfuscateIndex(project, guardExtension, mappingFile)
}
val mapping = XmlClassMapping(guardExtension)
if (!mappingFile.exists()) {
return mapping.apply { this.obfuscateIndex = obfuscateIndex }
}
parse(mappingFile) { line, mappingType, rawName, value ->
when (mappingType) {
DIR_MAPPING -> {
// 白名单
if (mapping.inWhiteList(rawName, isDirMapping = true)) {
return@parse
}
val obfuscateName = (value.split(".").lastOrNull() ?: value).lowercase()
if (obfuscateName.inPackageNameBlackList()) {
throw IllegalArgumentException("`${line.trim()}` is illegal, $obfuscateName is a keyword")
}
val minimumValue = obfuscateName.to26Long()
obfuscateIndex = obfuscateIndex.coerceAtLeast(minimumValue)
mapping.dirMapping[rawName] = value
}
CLASS_MAPPING -> {
// 白名单
if (mapping.inWhiteList(rawName)) {
return@parse
}
val index = value.lastIndexOf(".")
if (index == -1) {
//混淆路径必须要有包名
throw IllegalArgumentException("`$value` is illegal, must have a package name")
}
val obfuscateClassPath = value.substring(0, index) //混淆后的包名
val obfuscateClassName = value.substring(index + 1) //混淆后的类名
if (obfuscateClassName.inClassNameBlackList()) {
throw IllegalArgumentException("`$value` is illegal, It cannot be defined as a class name")
}
val dirMapping = mapping.dirMapping
if (!dirMapping.containsValue(obfuscateClassPath)) {
val rawClassPath = rawName.substring(0, rawName.lastIndexOf(".")) //原始包名
if (dirMapping.containsKey(rawClassPath)) {
//类混淆的真实路径与混淆的目录不匹配
throw IllegalArgumentException("$rawName -> $value is illegal should be\n$rawName -> ${dirMapping[rawClassPath]}.$obfuscateClassName")
}
dirMapping[rawClassPath] = obfuscateClassPath
}
val minimumValue = obfuscateClassName.to26Long()
obfuscateIndex = obfuscateIndex.coerceAtLeast(minimumValue)
mapping.classMapping[rawName] = value
}
}
}
mapping.obfuscateIndex = mapping.obfuscateIndex.coerceAtLeast(obfuscateIndex)
return mapping
}
fun parse(
mappingFile: File,
callback: (line: String, mappingType: String, key: String, value: String) -> Unit
) {
if (!mappingFile.exists() || !mappingFile.isFile) return
var mappingType = ""
mappingFile.forEachLine { line ->
val mat = mappingPattern.matcher(line)
if (mat.find()) {
val key = mat.group(1).trim()
val value = mat.group(2).trim()
callback.invoke(line, mappingType, key, value)
} else {
mappingType = line
}
}
}
private fun compareObfuscateIndex(
project: Project,
guardExtension: GuardExtension,
mappingFile: File,
): Long {
var obfuscateIndex = -1L
val mappingFileName = if (mappingFile.exists()) mappingFile.name else ""
if (mappingFileName != MAPPING_RES) {
val mapping = parseRes(project, guardExtension, project.file(MAPPING_RES))
obfuscateIndex = obfuscateIndex.coerceAtLeast(mapping.obfuscateIndex)
}
if (mappingFileName != MAPPING_XML_CLASS) {
val mapping = parseXmlClass(project, guardExtension, project.file(MAPPING_XML_CLASS))
obfuscateIndex = obfuscateIndex.coerceAtLeast(mapping.obfuscateIndex)
}
if (mappingFileName != MAPPING_STRING_FOR) {
val mapping = parseStringFog(project, guardExtension, project.file(MAPPING_STRING_FOR))
obfuscateIndex = obfuscateIndex.coerceAtLeast(mapping.obfuscateIndex)
}
if (mappingFileName != MAPPING_DECLARATION) {
val mapping =
parseDeclaration(project, guardExtension, project.file(MAPPING_DECLARATION))
obfuscateIndex = obfuscateIndex.coerceAtLeast(mapping.obfuscateIndex)
}
if (mappingFileName != MAPPING_CUSTOM_STRING) {
val mapping =
parseCustomString(project, guardExtension, project.file(MAPPING_CUSTOM_STRING))
obfuscateIndex = obfuscateIndex.coerceAtLeast(mapping.obfuscateIndex)
}
return obfuscateIndex
}
}