1 /* 2 * Copyright (C) 2008 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.dx.dex.file; 18 19 import com.android.dx.rop.annotation.Annotation; 20 import static com.android.dx.rop.annotation.AnnotationVisibility.SYSTEM; 21 import com.android.dx.rop.annotation.NameValuePair; 22 import com.android.dx.rop.cst.Constant; 23 import com.android.dx.rop.cst.CstAnnotation; 24 import com.android.dx.rop.cst.CstArray; 25 import com.android.dx.rop.cst.CstInteger; 26 import com.android.dx.rop.cst.CstKnownNull; 27 import com.android.dx.rop.cst.CstMethodRef; 28 import com.android.dx.rop.cst.CstString; 29 import com.android.dx.rop.cst.CstType; 30 import com.android.dx.rop.type.Type; 31 import com.android.dx.rop.type.TypeList; 32 import java.util.ArrayList; 33 34 /** 35 * Utility class for dealing with annotations. 36 */ 37 public final class AnnotationUtils { 38 39 /** {@code non-null;} type for {@code AnnotationDefault} annotations */ 40 private static final CstType ANNOTATION_DEFAULT_TYPE = 41 CstType.intern(Type.intern("Ldalvik/annotation/AnnotationDefault;")); 42 43 /** {@code non-null;} type for {@code EnclosingClass} annotations */ 44 private static final CstType ENCLOSING_CLASS_TYPE = 45 CstType.intern(Type.intern("Ldalvik/annotation/EnclosingClass;")); 46 47 /** {@code non-null;} type for {@code EnclosingMethod} annotations */ 48 private static final CstType ENCLOSING_METHOD_TYPE = 49 CstType.intern(Type.intern("Ldalvik/annotation/EnclosingMethod;")); 50 51 /** {@code non-null;} type for {@code InnerClass} annotations */ 52 private static final CstType INNER_CLASS_TYPE = 53 CstType.intern(Type.intern("Ldalvik/annotation/InnerClass;")); 54 55 /** {@code non-null;} type for {@code MemberClasses} annotations */ 56 private static final CstType MEMBER_CLASSES_TYPE = 57 CstType.intern(Type.intern("Ldalvik/annotation/MemberClasses;")); 58 59 /** {@code non-null;} type for {@code Signature} annotations */ 60 private static final CstType SIGNATURE_TYPE = 61 CstType.intern(Type.intern("Ldalvik/annotation/Signature;")); 62 63 /** {@code non-null;} type for {@code SourceDebugExtension} annotations */ 64 private static final CstType SOURCE_DEBUG_EXTENSION_TYPE = 65 CstType.intern(Type.intern("Ldalvik/annotation/SourceDebugExtension;")); 66 67 /** {@code non-null;} type for {@code Throws} annotations */ 68 private static final CstType THROWS_TYPE = 69 CstType.intern(Type.intern("Ldalvik/annotation/Throws;")); 70 71 /** {@code non-null;} the UTF-8 constant {@code "accessFlags"} */ 72 private static final CstString ACCESS_FLAGS_STRING = new CstString("accessFlags"); 73 74 /** {@code non-null;} the UTF-8 constant {@code "name"} */ 75 private static final CstString NAME_STRING = new CstString("name"); 76 77 /** {@code non-null;} the UTF-8 constant {@code "value"} */ 78 private static final CstString VALUE_STRING = new CstString("value"); 79 80 /** 81 * This class is uninstantiable. 82 */ AnnotationUtils()83 private AnnotationUtils() { 84 // This space intentionally left blank. 85 } 86 87 /** 88 * Constructs a standard {@code AnnotationDefault} annotation. 89 * 90 * @param defaults {@code non-null;} the defaults, itself as an annotation 91 * @return {@code non-null;} the constructed annotation 92 */ makeAnnotationDefault(Annotation defaults)93 public static Annotation makeAnnotationDefault(Annotation defaults) { 94 Annotation result = new Annotation(ANNOTATION_DEFAULT_TYPE, SYSTEM); 95 96 result.put(new NameValuePair(VALUE_STRING, new CstAnnotation(defaults))); 97 result.setImmutable(); 98 return result; 99 } 100 101 /** 102 * Constructs a standard {@code EnclosingClass} annotation. 103 * 104 * @param clazz {@code non-null;} the enclosing class 105 * @return {@code non-null;} the annotation 106 */ makeEnclosingClass(CstType clazz)107 public static Annotation makeEnclosingClass(CstType clazz) { 108 Annotation result = new Annotation(ENCLOSING_CLASS_TYPE, SYSTEM); 109 110 result.put(new NameValuePair(VALUE_STRING, clazz)); 111 result.setImmutable(); 112 return result; 113 } 114 115 /** 116 * Constructs a standard {@code EnclosingMethod} annotation. 117 * 118 * @param method {@code non-null;} the enclosing method 119 * @return {@code non-null;} the annotation 120 */ makeEnclosingMethod(CstMethodRef method)121 public static Annotation makeEnclosingMethod(CstMethodRef method) { 122 Annotation result = new Annotation(ENCLOSING_METHOD_TYPE, SYSTEM); 123 124 result.put(new NameValuePair(VALUE_STRING, method)); 125 result.setImmutable(); 126 return result; 127 } 128 129 /** 130 * Constructs a standard {@code InnerClass} annotation. 131 * 132 * @param name {@code null-ok;} the original name of the class, or 133 * {@code null} to represent an anonymous class 134 * @param accessFlags the original access flags 135 * @return {@code non-null;} the annotation 136 */ makeInnerClass(CstString name, int accessFlags)137 public static Annotation makeInnerClass(CstString name, int accessFlags) { 138 Annotation result = new Annotation(INNER_CLASS_TYPE, SYSTEM); 139 Constant nameCst = (name != null) ? name : CstKnownNull.THE_ONE; 140 141 result.put(new NameValuePair(NAME_STRING, nameCst)); 142 result.put(new NameValuePair(ACCESS_FLAGS_STRING, 143 CstInteger.make(accessFlags))); 144 result.setImmutable(); 145 return result; 146 } 147 148 /** 149 * Constructs a standard {@code MemberClasses} annotation. 150 * 151 * @param types {@code non-null;} the list of (the types of) the member classes 152 * @return {@code non-null;} the annotation 153 */ makeMemberClasses(TypeList types)154 public static Annotation makeMemberClasses(TypeList types) { 155 CstArray array = makeCstArray(types); 156 Annotation result = new Annotation(MEMBER_CLASSES_TYPE, SYSTEM); 157 result.put(new NameValuePair(VALUE_STRING, array)); 158 result.setImmutable(); 159 return result; 160 } 161 162 /** 163 * Constructs a standard {@code Signature} annotation. 164 * 165 * @param signature {@code non-null;} the signature string 166 * @return {@code non-null;} the annotation 167 */ makeSignature(CstString signature)168 public static Annotation makeSignature(CstString signature) { 169 Annotation result = new Annotation(SIGNATURE_TYPE, SYSTEM); 170 171 /* 172 * Split the string into pieces that are likely to be common 173 * across many signatures and the rest of the file. 174 */ 175 176 String raw = signature.getString(); 177 int rawLength = raw.length(); 178 ArrayList<String> pieces = new ArrayList<String>(20); 179 180 for (int at = 0; at < rawLength; /*at*/) { 181 char c = raw.charAt(at); 182 int endAt = at + 1; 183 if (c == 'L') { 184 // Scan to ';' or '<'. Consume ';' but not '<'. 185 while (endAt < rawLength) { 186 c = raw.charAt(endAt); 187 if (c == ';') { 188 endAt++; 189 break; 190 } else if (c == '<') { 191 break; 192 } 193 endAt++; 194 } 195 } else { 196 // Scan to 'L' without consuming it. 197 while (endAt < rawLength) { 198 c = raw.charAt(endAt); 199 if (c == 'L') { 200 break; 201 } 202 endAt++; 203 } 204 } 205 206 pieces.add(raw.substring(at, endAt)); 207 at = endAt; 208 } 209 210 int size = pieces.size(); 211 CstArray.List list = new CstArray.List(size); 212 213 for (int i = 0; i < size; i++) { 214 list.set(i, new CstString(pieces.get(i))); 215 } 216 217 list.setImmutable(); 218 219 result.put(new NameValuePair(VALUE_STRING, new CstArray(list))); 220 result.setImmutable(); 221 return result; 222 } 223 224 /** 225 * Constructs a standard {@code SourceDebugExtension} annotation. 226 * 227 * @param smapString {@code non-null;} the SMAP string associated with 228 * @return {@code non-null;} the annotation 229 */ makeSourceDebugExtension(CstString smapString)230 public static Annotation makeSourceDebugExtension(CstString smapString) { 231 Annotation result = new Annotation(SOURCE_DEBUG_EXTENSION_TYPE, SYSTEM); 232 233 result.put(new NameValuePair(VALUE_STRING, smapString)); 234 result.setImmutable(); 235 return result; 236 } 237 238 /** 239 * Constructs a standard {@code Throws} annotation. 240 * 241 * @param types {@code non-null;} the list of thrown types 242 * @return {@code non-null;} the annotation 243 */ makeThrows(TypeList types)244 public static Annotation makeThrows(TypeList types) { 245 CstArray array = makeCstArray(types); 246 Annotation result = new Annotation(THROWS_TYPE, SYSTEM); 247 result.put(new NameValuePair(VALUE_STRING, array)); 248 result.setImmutable(); 249 return result; 250 } 251 252 /** 253 * Converts a {@link TypeList} to a {@link CstArray}. 254 * 255 * @param types {@code non-null;} the type list 256 * @return {@code non-null;} the corresponding array constant 257 */ makeCstArray(TypeList types)258 private static CstArray makeCstArray(TypeList types) { 259 int size = types.size(); 260 CstArray.List list = new CstArray.List(size); 261 262 for (int i = 0; i < size; i++) { 263 list.set(i, CstType.intern(types.getType(i))); 264 } 265 266 list.setImmutable(); 267 return new CstArray(list); 268 } 269 } 270