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