1 /* <lambda>null2 * Copyright (C) 2023 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 package com.android.hoststubgen.visitors 17 18 import com.android.hoststubgen.asm.toJvmClassName 19 import org.objectweb.asm.commons.Remapper 20 21 /** 22 * A [Remapper] for `--package-redirect` 23 */ 24 class PackageRedirectRemapper( 25 packageRedirects: List<Pair<String, String>>, 26 ) : Remapper() { 27 28 /** 29 * Example: `dalvik/` -> `com/android/hostsubgen/substitution/dalvik/` 30 */ 31 private val packageRedirectsWithSlash: List<Pair<String, String>> = packageRedirects.map { 32 p -> Pair(p.first.toJvmClassName() + "/", p.second.toJvmClassName() + "/") 33 } 34 35 /** 36 * Cache. 37 * If a class is a redirect-from class, then the "to" class name will be stored as the value. 38 * Otherwise, "" will be stored. 39 */ 40 private val cache = mutableMapOf<String, String>() 41 42 /** 43 * Return whether any redirect is defined. 44 */ 45 val isEmpty get() = packageRedirectsWithSlash.isEmpty() 46 47 override fun map(internalName: String?): String? { 48 if (internalName == null) { 49 return null 50 } 51 val to = mapInner(internalName) 52 return to ?: internalName 53 } 54 55 /** 56 * Internal "map" function. Unlike [map(String)], this method will return null 57 * if a class is not a redirect-from class. 58 */ 59 private fun mapInner(internalName: String): String? { 60 cache[internalName]?.let { 61 return if (it.isEmpty()) null else it 62 } 63 64 var ret = "" 65 packageRedirectsWithSlash.forEach { fromTo -> 66 if (internalName.startsWith(fromTo.first)) { 67 ret = fromTo.second + internalName.substring(fromTo.first.length) 68 } 69 } 70 cache.set(internalName, ret) 71 72 return if (ret.isEmpty()) null else ret 73 } 74 75 /** 76 * Return true if a class is a redirect-from class. 77 */ 78 fun isTarget(internalName: String): Boolean { 79 return mapInner(internalName) != null 80 } 81 } 82 83