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