1 /*
2  * Copyright (C) 2009 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 dex.reader;
18 
19 import java.lang.reflect.Modifier;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.LinkedList;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Set;
26 
27 import dex.reader.DexClassImpl.MethodAnnotation;
28 import dex.reader.DexClassImpl.ParameterAnnotation;
29 import dex.reader.DexFileReader.FieldIdItem;
30 import dex.reader.DexFileReader.MethodsIdItem;
31 import dex.reader.DexFileReader.ProtIdItem;
32 import dex.structure.DexAnnotation;
33 import dex.structure.DexClass;
34 import dex.structure.DexMethod;
35 import dex.structure.DexParameter;
36 
37 /* package */final class DexMethodImpl implements DexMethod {
38 
39     private DexBuffer buffer;
40     private MethodsIdItem methodsIdItem;
41     private String[] stringPool;
42     private int[] typeIds;
43     private ProtIdItem protoIdItem;
44     private List<DexParameter> parameters;
45     private final int accessFlags;
46     private final MethodAnnotation methodAnnotation;
47     private Set<DexAnnotation> annotations;
48     private final TypeFormatter formatter = new TypeFormatter();
49     private final DexClass declaringClass;
50     private final ParameterAnnotation parameterAnnotation;
51     private Map<Integer, Integer> parameterIdToIndex;
52     private final FieldIdItem[] fieldIdItems;
53 
DexMethodImpl(DexBuffer buffer, DexClass declaringClass, MethodsIdItem methodsIdItem, ProtIdItem protoIdItem, int accessFlags, MethodAnnotation methodAnnotation, ParameterAnnotation parameterAnnotation, String[] stringPool, int[] typeIds, FieldIdItem[] fieldIdItems)54     public DexMethodImpl(DexBuffer buffer, DexClass declaringClass,
55             MethodsIdItem methodsIdItem, ProtIdItem protoIdItem,
56             int accessFlags, MethodAnnotation methodAnnotation,
57             ParameterAnnotation parameterAnnotation, String[] stringPool,
58             int[] typeIds, FieldIdItem[] fieldIdItems) {
59         this.buffer = buffer;
60         this.declaringClass = declaringClass;
61         this.methodsIdItem = methodsIdItem;
62         this.protoIdItem = protoIdItem;
63         this.accessFlags = accessFlags;
64         this.methodAnnotation = methodAnnotation;
65         this.parameterAnnotation = parameterAnnotation;
66         this.stringPool = stringPool;
67         this.typeIds = typeIds;
68         this.fieldIdItems = fieldIdItems;
69         parseAnnotations();
70         parseParameterAnnotations();
71     }
72 
parseParameterAnnotations()73     private void parseParameterAnnotations() {
74         parameterIdToIndex = new HashMap<Integer, Integer>();
75         if (parameterAnnotation != null) {
76             buffer.setPosition(parameterAnnotation.annotationsOff);
77             int numberOfParameters = buffer.readUInt();
78             for (int i = 0; i < numberOfParameters; i++) {
79                 parameterIdToIndex.put(i, buffer.readUInt());
80             }
81         }
82     }
83 
parseAnnotations()84     private void parseAnnotations() {
85         annotations = new HashSet<DexAnnotation>();
86         if (methodAnnotation != null) {
87             buffer.setPosition(methodAnnotation.annotationsOff);
88             final int size = buffer.readUInt();
89             for (int i = 0; i < size; i++) {
90                 annotations.add(new DexAnnotationImpl(buffer.createCopy(),
91                         buffer.readUInt(), typeIds, stringPool, fieldIdItems));
92             }
93         }
94     }
95 
getName()96     public String getName() {
97         return stringPool[methodsIdItem.name_idx];
98     }
99 
getReturnType()100     public String getReturnType() {
101         return stringPool[typeIds[protoIdItem.return_type_idx]];
102     }
103 
getParameters()104     public synchronized List<DexParameter> getParameters() {
105         if (parameters == null) {
106             parameters = new LinkedList<DexParameter>();
107             if (protoIdItem.parameter_off != 0) {
108 
109                 buffer.setPosition(protoIdItem.parameter_off);
110                 int size = buffer.readUInt();
111 
112                 int[] paramTypeIdx = new int[size];
113                 for (int i = 0; i < size; i++) {
114                     paramTypeIdx[i] = buffer.readUShort();
115                 }
116                 for (int i = 0; i < paramTypeIdx.length; i++) {
117                     parameters.add(new DexParameterImpl(buffer.createCopy(),
118                             stringPool[typeIds[paramTypeIdx[i]]],
119                             parameterIdToIndex.get(i), typeIds, stringPool,
120                             fieldIdItems));
121                 }
122             }
123         }
124         return parameters;
125     }
126 
getModifiers()127     public int getModifiers() {
128         return accessFlags;
129     }
130 
getAnnotations()131     public Set<DexAnnotation> getAnnotations() {
132         return annotations;
133     }
134 
getDeclaringClass()135     public DexClass getDeclaringClass() {
136         return declaringClass;
137     }
138 
139     @Override
toString()140     public String toString() {
141         StringBuilder builder = new StringBuilder();
142         builder.append(formatter.formatAnnotations(getAnnotations()));
143         builder.append(Modifier.toString(getModifiers()));
144         builder.append(" ");
145         builder.append(formatter.format(getReturnType()));
146         builder.append(" ");
147         builder.append(getName());
148         builder.append("(");
149         List<DexParameter> parameters = getParameters();
150         for (DexParameter dexParameter : parameters) {
151             builder.append(formatter.formatAnnotations(dexParameter
152                     .getAnnotations()));
153             builder.append(formatter.format(dexParameter.getTypeName()));
154         }
155         builder.append(")");
156         return builder.toString();
157     }
158 }
159