1 /* <lambda>null2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.xts.apimapper.asm 18 19 import java.io.BufferedInputStream 20 import java.util.HashMap 21 import java.util.zip.ZipFile 22 import org.objectweb.asm.ClassReader 23 import org.objectweb.asm.tree.ClassNode 24 import org.objectweb.asm.tree.MethodNode 25 26 /** Load all classes from a .jar file. */ 27 fun loadClassStructure(inJar: String): ClassNodes { 28 val allClasses = ClassNodes(inJar) 29 30 ZipFile(inJar).use { inZip -> 31 val inEntries = inZip.entries() 32 while (inEntries.hasMoreElements()) { 33 val entry = inEntries.nextElement() 34 if (!entry.name.endsWith(".class")) { 35 continue 36 } 37 val bis = BufferedInputStream(inZip.getInputStream(entry)) 38 val cr = ClassReader(bis) 39 val cn = ClassNode() 40 cr.accept( 41 cn, 42 ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES 43 ) 44 allClasses.addClass(cn) 45 } 46 } 47 return allClasses 48 } 49 50 /** Store all classes loaded from a jar file. */ 51 class ClassNodes(val sourceJarFile: String) { 52 53 private val mClasses: MutableMap<String, ClassNode> = HashMap() 54 55 /** Add a class node. */ addClassnull56 fun addClass(node: ClassNode) { 57 mClasses.putIfAbsent(node.name.toJvmClassName(), node) 58 } 59 60 /** Find the ClassNode with the given class name. */ findClassnull61 fun findClass(className: String): ClassNode? { 62 return mClasses[className.toJvmClassName()] 63 } 64 65 /** Check whether the given class exists or not. */ hasClassnull66 fun hasClass(className: String): Boolean { 67 return mClasses.containsKey(className.toJvmClassName()) 68 } 69 70 /** Find the method member of a class. Returns null if it doesn't exist. */ findMethodnull71 fun findMethod(className: String, methodName: String, desc: String): MethodNode? { 72 return findClass(className)?.methods?.firstOrNull { 73 it.name == methodName && it.desc == desc }?.let { node -> return node } 74 } 75 76 /** @return true if a class has a class initializer. */ hasClassInitializernull77 fun hasClassInitializer(className: String): Boolean { 78 return findMethod(className, CLASS_INITIALIZER_NAME, CLASS_INITIALIZER_DESC) != null 79 } 80 } 81