All Downloads are FREE. Search and download functionalities are using the official Maven repository.
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.
com.jrhlive.libasm.util.AsmUtils.kt Maven / Gradle / Ivy
package com.jrhlive.libasm.util
import com.android.build.api.transform.Context
import org.apache.commons.codec.digest.DigestUtils
import org.apache.commons.io.IOUtils
import org.objectweb.asm.ClassReader
import org.objectweb.asm.ClassWriter
import java.io.*
import java.util.jar.JarFile
import java.util.jar.JarOutputStream
import java.util.zip.ZipEntry
object AsmUtils {
val extensions = arrayListOf()
fun readBytes(inputStream: InputStream): ByteArray? {
val byteArrayOutputStream = ByteArrayOutputStream()
try {
val buffer = ByteArray(1024)
var len: Int
while (inputStream.read(buffer).apply { len = this } != -1) {
byteArrayOutputStream.write(buffer, 0, len)
}
byteArrayOutputStream.flush()
return byteArrayOutputStream.toByteArray()
} catch (ex: Exception) {
ex.printStackTrace()
} finally {
byteArrayOutputStream.close()
inputStream.close()
}
return null
}
fun byte2File(outputPath: String, sourceByte: ByteArray) {
val file = File(outputPath)
if (file.exists()) {
file.delete()
}
val inputStream = ByteArrayInputStream(sourceByte)
val outputStream = FileOutputStream(file)
val buffer = ByteArray(1024)
var len: Int
while (inputStream.read(buffer).apply { len = this } != -1) {
outputStream.write(buffer, 0, len)
}
outputStream.flush()
outputStream.close()
inputStream.close()
}
fun replaceInJar(context: Context, file: File): File? {
val tempDir = context.temporaryDir
if (isNeedModifyJar(file)) {
modifyJar(file, tempDir, true)
}
return null
}
fun classFileDir(extension: PlaceholderExtension): String {
return if (extension.classFileToReplace.isNotEmpty())
extension.classFileToReplace.substring(0, extension.classFileToReplace.lastIndexOf("/"))
else ""
}
private fun modifyJar(jarFile: File, tempDir: File?, nameHex: Boolean):File {
/**
* 读取原jar
*/
val file = JarFile(jarFile)
/** 设置输出到的jar */
var hexName = ""
if (nameHex) {
hexName = DigestUtils.md5Hex(jarFile.absolutePath).substring(0, 8)
}
val outputJar = File(tempDir, hexName + jarFile.name)
val jarOutputStream = JarOutputStream( FileOutputStream(outputJar))
val enumeration = file.entries()
while (enumeration.hasMoreElements()) {
val jarEntry = enumeration.nextElement()
val inputStream = file.getInputStream(jarEntry)
val entryName = jarEntry.name
var className=""
val zipEntry = ZipEntry(entryName)
jarOutputStream.putNextEntry(zipEntry)
var modifiedClassBytes:ByteArray? = null
val sourceClassBytes = IOUtils.toByteArray(inputStream)
if (entryName.endsWith(".class")) {
className = entryName.replace(".class", "")
modifiedClassBytes = modifyClasses(className, sourceClassBytes)
}
if (modifiedClassBytes == null) {
jarOutputStream.write(sourceClassBytes)
} else {
jarOutputStream.write(modifiedClassBytes)
}
jarOutputStream.closeEntry()
}
jarOutputStream.close()
file.close()
return outputJar
}
fun modifyClasses( className:String ,srcByteCode:ByteArray?):ByteArray? {
val modifyMap = modifyMap(className)
var classBytesCode:ByteArray? = null
modifyMap?.let {
try {
println("--> start modifying $className")
classBytesCode = modifyClass(srcByteCode, modifyMap, false)
println("--> revisit modified $className")
modifyClass(srcByteCode, modifyMap, true)
println("--> finish modifying $className")
return classBytesCode
} catch ( e:Exception) {
e.printStackTrace()
}
}
if (classBytesCode == null) {
classBytesCode = srcByteCode
}
return classBytesCode
}
private fun modifyClass(srcByteCode: ByteArray?, modifyMap: Map, isOnlyVisit: Boolean): ByteArray? {
val classWriter = ClassWriter(ClassWriter.COMPUTE_MAXS)
// val adapter = ClassFilterVisitor(classWriter, modifyMap)
// adapter.isOnlyVisit = isOnlyVisit
// val cr = ClassReader(srcByteCode)
// cr.accept(adapter, 0)
return classWriter.toByteArray()
}
fun modifyMap( className:String?) :Map?{
if (className?.trim()?.isNotEmpty()==true){
if (extensions.isEmpty()) return null
val values = mutableMapOf()
extensions.find {
val name = String.format("%s/%s", classFileDir(it), classFileName(it))
if (name == className) {
values.putAll(it.replaceValues)
true
} else
false
}
return values
}
return null
}
//是否修改jar
private fun isNeedModifyJar(jarFile: File): Boolean {
if (extensions.isNullOrEmpty()) return false
var modify = false
val file = JarFile(jarFile)
val entries = file.entries()
while (entries.hasMoreElements()) {
val entry = entries.nextElement()
val isModify = extensions.any {
val name = String.format("s%/%s", classFileDir(it), classFileNameWithClass(it))
return if (name == entry.name) {
modify = true
true
} else false
}
if (isModify) break
}
file.close()
return modify
}
private fun classFileNameWithClass(extension: PlaceholderExtension): String? {
return classFileName(extension) + ".class"
}
fun classFileName(extension: PlaceholderExtension?): String {
extension?.classFileToReplace?.let {
if (it.isNotEmpty()) {
return it.substring(it.lastIndexOf("/") + 1, it.lastIndexOf("."))
}
}
return ""
}
fun getClassFileName(filePath:String):String{
try {
if (filePath.isNotEmpty()){
return filePath.substring(filePath.lastIndexOf("/") + 1, filePath.lastIndexOf("."))
}
}catch (e:Exception){
}
return ""
}
fun changeClassFileName(fileName:String):String{
return fileName.replace("/",".")
}
}