| /* |
| * Copyright (C) 2008 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.dx.dex.file; |
| |
| import static com.android.dx.rop.annotation.AnnotationVisibility.SYSTEM; |
| |
| import com.android.dx.rop.annotation.Annotation; |
| import com.android.dx.rop.annotation.NameValuePair; |
| import com.android.dx.rop.cst.Constant; |
| import com.android.dx.rop.cst.CstAnnotation; |
| import com.android.dx.rop.cst.CstArray; |
| import com.android.dx.rop.cst.CstInteger; |
| import com.android.dx.rop.cst.CstKnownNull; |
| import com.android.dx.rop.cst.CstMethodRef; |
| import com.android.dx.rop.cst.CstString; |
| import com.android.dx.rop.cst.CstType; |
| import com.android.dx.rop.type.Type; |
| import com.android.dx.rop.type.TypeList; |
| |
| import java.util.ArrayList; |
| |
| /** |
| * Utility class for dealing with annotations. |
| */ |
| public final class AnnotationUtils { |
| |
| /** {@code non-null;} type for {@code AnnotationDefault} annotations */ |
| private static final CstType ANNOTATION_DEFAULT_TYPE = |
| CstType.intern(Type.intern("Ldalvik/annotation/AnnotationDefault;")); |
| |
| /** {@code non-null;} type for {@code EnclosingClass} annotations */ |
| private static final CstType ENCLOSING_CLASS_TYPE = |
| CstType.intern(Type.intern("Ldalvik/annotation/EnclosingClass;")); |
| |
| /** {@code non-null;} type for {@code EnclosingMethod} annotations */ |
| private static final CstType ENCLOSING_METHOD_TYPE = |
| CstType.intern(Type.intern("Ldalvik/annotation/EnclosingMethod;")); |
| |
| /** {@code non-null;} type for {@code InnerClass} annotations */ |
| private static final CstType INNER_CLASS_TYPE = |
| CstType.intern(Type.intern("Ldalvik/annotation/InnerClass;")); |
| |
| /** {@code non-null;} type for {@code MemberClasses} annotations */ |
| private static final CstType MEMBER_CLASSES_TYPE = |
| CstType.intern(Type.intern("Ldalvik/annotation/MemberClasses;")); |
| |
| /** {@code non-null;} type for {@code Signature} annotations */ |
| private static final CstType SIGNATURE_TYPE = |
| CstType.intern(Type.intern("Ldalvik/annotation/Signature;")); |
| |
| /** {@code non-null;} type for {@code SourceDebugExtension} annotations */ |
| private static final CstType SOURCE_DEBUG_EXTENSION_TYPE = |
| CstType.intern(Type.intern("Ldalvik/annotation/SourceDebugExtension;")); |
| |
| /** {@code non-null;} type for {@code Throws} annotations */ |
| private static final CstType THROWS_TYPE = |
| CstType.intern(Type.intern("Ldalvik/annotation/Throws;")); |
| |
| /** {@code non-null;} the UTF-8 constant {@code "accessFlags"} */ |
| private static final CstString ACCESS_FLAGS_STRING = new CstString("accessFlags"); |
| |
| /** {@code non-null;} the UTF-8 constant {@code "name"} */ |
| private static final CstString NAME_STRING = new CstString("name"); |
| |
| /** {@code non-null;} the UTF-8 constant {@code "value"} */ |
| private static final CstString VALUE_STRING = new CstString("value"); |
| |
| /** |
| * This class is uninstantiable. |
| */ |
| private AnnotationUtils() { |
| // This space intentionally left blank. |
| } |
| |
| /** |
| * Constructs a standard {@code AnnotationDefault} annotation. |
| * |
| * @param defaults {@code non-null;} the defaults, itself as an annotation |
| * @return {@code non-null;} the constructed annotation |
| */ |
| public static Annotation makeAnnotationDefault(Annotation defaults) { |
| Annotation result = new Annotation(ANNOTATION_DEFAULT_TYPE, SYSTEM); |
| |
| result.put(new NameValuePair(VALUE_STRING, new CstAnnotation(defaults))); |
| result.setImmutable(); |
| return result; |
| } |
| |
| /** |
| * Constructs a standard {@code EnclosingClass} annotation. |
| * |
| * @param clazz {@code non-null;} the enclosing class |
| * @return {@code non-null;} the annotation |
| */ |
| public static Annotation makeEnclosingClass(CstType clazz) { |
| Annotation result = new Annotation(ENCLOSING_CLASS_TYPE, SYSTEM); |
| |
| result.put(new NameValuePair(VALUE_STRING, clazz)); |
| result.setImmutable(); |
| return result; |
| } |
| |
| /** |
| * Constructs a standard {@code EnclosingMethod} annotation. |
| * |
| * @param method {@code non-null;} the enclosing method |
| * @return {@code non-null;} the annotation |
| */ |
| public static Annotation makeEnclosingMethod(CstMethodRef method) { |
| Annotation result = new Annotation(ENCLOSING_METHOD_TYPE, SYSTEM); |
| |
| result.put(new NameValuePair(VALUE_STRING, method)); |
| result.setImmutable(); |
| return result; |
| } |
| |
| /** |
| * Constructs a standard {@code InnerClass} annotation. |
| * |
| * @param name {@code null-ok;} the original name of the class, or |
| * {@code null} to represent an anonymous class |
| * @param accessFlags the original access flags |
| * @return {@code non-null;} the annotation |
| */ |
| public static Annotation makeInnerClass(CstString name, int accessFlags) { |
| Annotation result = new Annotation(INNER_CLASS_TYPE, SYSTEM); |
| Constant nameCst = (name != null) ? name : CstKnownNull.THE_ONE; |
| |
| result.put(new NameValuePair(NAME_STRING, nameCst)); |
| result.put(new NameValuePair(ACCESS_FLAGS_STRING, |
| CstInteger.make(accessFlags))); |
| result.setImmutable(); |
| return result; |
| } |
| |
| /** |
| * Constructs a standard {@code MemberClasses} annotation. |
| * |
| * @param types {@code non-null;} the list of (the types of) the member classes |
| * @return {@code non-null;} the annotation |
| */ |
| public static Annotation makeMemberClasses(TypeList types) { |
| CstArray array = makeCstArray(types); |
| Annotation result = new Annotation(MEMBER_CLASSES_TYPE, SYSTEM); |
| result.put(new NameValuePair(VALUE_STRING, array)); |
| result.setImmutable(); |
| return result; |
| } |
| |
| /** |
| * Constructs a standard {@code Signature} annotation. |
| * |
| * @param signature {@code non-null;} the signature string |
| * @return {@code non-null;} the annotation |
| */ |
| public static Annotation makeSignature(CstString signature) { |
| Annotation result = new Annotation(SIGNATURE_TYPE, SYSTEM); |
| |
| /* |
| * Split the string into pieces that are likely to be common |
| * across many signatures and the rest of the file. |
| */ |
| |
| String raw = signature.getString(); |
| int rawLength = raw.length(); |
| ArrayList<String> pieces = new ArrayList<String>(20); |
| |
| for (int at = 0; at < rawLength; /*at*/) { |
| char c = raw.charAt(at); |
| int endAt = at + 1; |
| if (c == 'L') { |
| // Scan to ';' or '<'. Consume ';' but not '<'. |
| while (endAt < rawLength) { |
| c = raw.charAt(endAt); |
| if (c == ';') { |
| endAt++; |
| break; |
| } else if (c == '<') { |
| break; |
| } |
| endAt++; |
| } |
| } else { |
| // Scan to 'L' without consuming it. |
| while (endAt < rawLength) { |
| c = raw.charAt(endAt); |
| if (c == 'L') { |
| break; |
| } |
| endAt++; |
| } |
| } |
| |
| pieces.add(raw.substring(at, endAt)); |
| at = endAt; |
| } |
| |
| int size = pieces.size(); |
| CstArray.List list = new CstArray.List(size); |
| |
| for (int i = 0; i < size; i++) { |
| list.set(i, new CstString(pieces.get(i))); |
| } |
| |
| list.setImmutable(); |
| |
| result.put(new NameValuePair(VALUE_STRING, new CstArray(list))); |
| result.setImmutable(); |
| return result; |
| } |
| |
| /** |
| * Constructs a standard {@code SourceDebugExtension} annotation. |
| * |
| * @param smapString {@code non-null;} the SMAP string associated with |
| * @return {@code non-null;} the annotation |
| */ |
| public static Annotation makeSourceDebugExtension(CstString smapString) { |
| Annotation result = new Annotation(SOURCE_DEBUG_EXTENSION_TYPE, SYSTEM); |
| |
| result.put(new NameValuePair(VALUE_STRING, smapString)); |
| result.setImmutable(); |
| return result; |
| } |
| |
| /** |
| * Constructs a standard {@code Throws} annotation. |
| * |
| * @param types {@code non-null;} the list of thrown types |
| * @return {@code non-null;} the annotation |
| */ |
| public static Annotation makeThrows(TypeList types) { |
| CstArray array = makeCstArray(types); |
| Annotation result = new Annotation(THROWS_TYPE, SYSTEM); |
| result.put(new NameValuePair(VALUE_STRING, array)); |
| result.setImmutable(); |
| return result; |
| } |
| |
| /** |
| * Converts a {@link TypeList} to a {@link CstArray}. |
| * |
| * @param types {@code non-null;} the type list |
| * @return {@code non-null;} the corresponding array constant |
| */ |
| private static CstArray makeCstArray(TypeList types) { |
| int size = types.size(); |
| CstArray.List list = new CstArray.List(size); |
| |
| for (int i = 0; i < size; i++) { |
| list.set(i, CstType.intern(types.getType(i))); |
| } |
| |
| list.setImmutable(); |
| return new CstArray(list); |
| } |
| } |