1 /*
2  * Copyright (C) 2018 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 android.signature.cts;
17 
18 import java.util.Arrays;
19 import java.util.Collections;
20 import java.util.HashSet;
21 import java.util.Set;
22 
23 /**
24  * Represents one class member parsed from the reader of dex signatures.
25  */
26 public abstract class DexMember {
27     private final String mName;
28     private final String mClassDescriptor;
29     private final String mType;
30     private final Set<String> mFlags;
31 
DexMember(String className, String name, String type, String[] flags)32     protected DexMember(String className, String name, String type, String[] flags) {
33         mName = name;
34         mClassDescriptor = className;
35         mType = type;
36         mFlags = flags == null ? Collections.emptySet() : new HashSet<>(Arrays.asList(flags));
37     }
38 
getName()39     public String getName() {
40         return mName;
41     }
42 
getDexClassName()43     public String getDexClassName() {
44         return mClassDescriptor;
45     }
46 
getJavaClassName()47     public String getJavaClassName() {
48         return dexToJavaType(mClassDescriptor);
49     }
50 
getDexType()51     public String getDexType() {
52         return mType;
53     }
54 
getJavaType()55     public String getJavaType() {
56         return dexToJavaType(mType);
57     }
58 
getHiddenapiFlags()59     public Set<String> getHiddenapiFlags() {
60         return mFlags;
61     }
62 
63     /**
64      * Converts `type` to a Java type.
65      */
dexToJavaType(String type)66     protected static String dexToJavaType(String type) {
67         String javaDimension = "";
68         while (type.startsWith("[")) {
69             javaDimension += "[]";
70             type = type.substring(1);
71         }
72 
73         String javaType = null;
74         if ("V".equals(type)) {
75             javaType = "void";
76         } else if ("Z".equals(type)) {
77             javaType = "boolean";
78         } else if ("B".equals(type)) {
79             javaType = "byte";
80         } else if ("C".equals(type)) {
81             javaType = "char";
82         } else if ("S".equals(type)) {
83             javaType = "short";
84         } else if ("I".equals(type)) {
85             javaType = "int";
86         } else if ("J".equals(type)) {
87             javaType = "long";
88         } else if ("F".equals(type)) {
89             javaType = "float";
90         } else if ("D".equals(type)) {
91             javaType = "double";
92         } else if (type.startsWith("L") && type.endsWith(";")) {
93             javaType = type.substring(1, type.length() - 1).replace('/', '.');
94         } else {
95             throw new IllegalStateException("Unexpected type " + type);
96         }
97 
98         return javaType + javaDimension;
99     }
100 
typeToClass(String type)101     public static Class<?> typeToClass(String type) throws ClassNotFoundException {
102         if ("V".equals(type)) {
103             return void.class;
104         } else if ("Z".equals(type)) {
105             return boolean.class;
106         } else if ("B".equals(type)) {
107             return byte.class;
108         } else if ("C".equals(type)) {
109             return char.class;
110         } else if ("S".equals(type)) {
111             return short.class;
112         } else if ("I".equals(type)) {
113             return int.class;
114         } else if ("J".equals(type)) {
115             return long.class;
116         } else if ("F".equals(type)) {
117             return float.class;
118         } else if ("D".equals(type)) {
119             return double.class;
120         } else {
121             // Class names expected for Class.forName are:
122             // * for reference types: Ljava/lang/String; -> java.lang.String
123             // * for array types: [Ljava/lang/String; -> [Ljava.lang.String;
124             type = type.startsWith("L")
125                     ? type.substring(1, type.length() - 1).replace('/', '.')
126                     : type.replace('/', '.');
127         }
128 
129         return Class.forName(type, /* initialize */ false, DexMember.class.getClassLoader());
130     }
131 }
132