• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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.merge;
18 
19 import com.android.dx.dex.TableOfContents;
20 import com.android.dx.io.Annotation;
21 import com.android.dx.io.ClassDef;
22 import com.android.dx.io.DexBuffer;
23 import com.android.dx.io.EncodedValue;
24 import com.android.dx.io.EncodedValueReader;
25 import com.android.dx.io.FieldId;
26 import com.android.dx.io.MethodId;
27 import com.android.dx.io.ProtoId;
28 import com.android.dx.util.ByteArrayAnnotatedOutput;
29 import com.android.dx.util.ByteInput;
30 import com.android.dx.util.ByteOutput;
31 import com.android.dx.util.Leb128Utils;
32 import com.android.dx.util.Unsigned;
33 import java.util.HashMap;
34 
35 /**
36  * Maps the index offsets from one dex file to those in another. For example, if
37  * you have string #5 in the old dex file, its position in the new dex file is
38  * {@code strings[5]}.
39  */
40 public final class IndexMap {
41     private final DexBuffer target;
42     public final int[] stringIds;
43     public final short[] typeIds;
44     public final short[] protoIds;
45     public final short[] fieldIds;
46     public final short[] methodIds;
47     private final HashMap<Integer, Integer> typeListOffsets;
48     private final HashMap<Integer, Integer> annotationOffsets;
49     private final HashMap<Integer, Integer> annotationSetOffsets;
50     private final HashMap<Integer, Integer> annotationDirectoryOffsets;
51     private final HashMap<Integer, Integer> staticValuesOffsets;
52 
IndexMap(DexBuffer target, TableOfContents tableOfContents)53     public IndexMap(DexBuffer target, TableOfContents tableOfContents) {
54         this.target = target;
55         this.stringIds = new int[tableOfContents.stringIds.size];
56         this.typeIds = new short[tableOfContents.typeIds.size];
57         this.protoIds = new short[tableOfContents.protoIds.size];
58         this.fieldIds = new short[tableOfContents.fieldIds.size];
59         this.methodIds = new short[tableOfContents.methodIds.size];
60         this.typeListOffsets = new HashMap<Integer, Integer>();
61         this.annotationOffsets = new HashMap<Integer, Integer>();
62         this.annotationSetOffsets = new HashMap<Integer, Integer>();
63         this.annotationDirectoryOffsets = new HashMap<Integer, Integer>();
64         this.staticValuesOffsets = new HashMap<Integer, Integer>();
65 
66         /*
67          * A type list, annotation set, annotation directory, or static value at
68          * offset 0 is always empty. Always map offset 0 to 0.
69          */
70         this.typeListOffsets.put(0, 0);
71         this.annotationSetOffsets.put(0, 0);
72         this.annotationDirectoryOffsets.put(0, 0);
73         this.staticValuesOffsets.put(0, 0);
74     }
75 
putTypeListOffset(int oldOffset, int newOffset)76     public void putTypeListOffset(int oldOffset, int newOffset) {
77         if (oldOffset <= 0 || newOffset <= 0) {
78             throw new IllegalArgumentException();
79         }
80         typeListOffsets.put(oldOffset, newOffset);
81     }
82 
putAnnotationOffset(int oldOffset, int newOffset)83     public void putAnnotationOffset(int oldOffset, int newOffset) {
84         if (oldOffset <= 0 || newOffset <= 0) {
85             throw new IllegalArgumentException();
86         }
87         annotationOffsets.put(oldOffset, newOffset);
88     }
89 
putAnnotationSetOffset(int oldOffset, int newOffset)90     public void putAnnotationSetOffset(int oldOffset, int newOffset) {
91         if (oldOffset <= 0 || newOffset <= 0) {
92             throw new IllegalArgumentException();
93         }
94         annotationSetOffsets.put(oldOffset, newOffset);
95     }
96 
putAnnotationDirectoryOffset(int oldOffset, int newOffset)97     public void putAnnotationDirectoryOffset(int oldOffset, int newOffset) {
98         if (oldOffset <= 0 || newOffset <= 0) {
99             throw new IllegalArgumentException();
100         }
101         annotationDirectoryOffsets.put(oldOffset, newOffset);
102     }
103 
putStaticValuesOffset(int oldOffset, int newOffset)104     public void putStaticValuesOffset(int oldOffset, int newOffset) {
105         if (oldOffset <= 0 || newOffset <= 0) {
106             throw new IllegalArgumentException();
107         }
108         staticValuesOffsets.put(oldOffset, newOffset);
109     }
110 
adjustString(int stringIndex)111     public int adjustString(int stringIndex) {
112         return stringIndex == ClassDef.NO_INDEX ? ClassDef.NO_INDEX : stringIds[stringIndex];
113     }
114 
adjustType(int typeIndex)115     public int adjustType(int typeIndex) {
116         return (typeIndex == ClassDef.NO_INDEX) ? ClassDef.NO_INDEX : (typeIds[typeIndex] & 0xffff);
117     }
118 
adjustTypeList(TypeList typeList)119     public TypeList adjustTypeList(TypeList typeList) {
120         if (typeList == TypeList.EMPTY) {
121             return typeList;
122         }
123         short[] types = typeList.getTypes().clone();
124         for (int i = 0; i < types.length; i++) {
125             types[i] = (short) adjustType(types[i]);
126         }
127         return new TypeList(target, types);
128     }
129 
adjustProto(int protoIndex)130     public int adjustProto(int protoIndex) {
131         return protoIds[protoIndex] & 0xffff;
132     }
133 
adjustField(int fieldIndex)134     public int adjustField(int fieldIndex) {
135         return fieldIds[fieldIndex] & 0xffff;
136     }
137 
adjustMethod(int methodIndex)138     public int adjustMethod(int methodIndex) {
139         return methodIds[methodIndex] & 0xffff;
140     }
141 
adjustTypeListOffset(int typeListOffset)142     public int adjustTypeListOffset(int typeListOffset) {
143         return typeListOffsets.get(typeListOffset);
144     }
145 
adjustAnnotation(int annotationOffset)146     public int adjustAnnotation(int annotationOffset) {
147         return annotationOffsets.get(annotationOffset);
148     }
149 
adjustAnnotationSet(int annotationSetOffset)150     public int adjustAnnotationSet(int annotationSetOffset) {
151         return annotationSetOffsets.get(annotationSetOffset);
152     }
153 
adjustAnnotationDirectory(int annotationDirectoryOffset)154     public int adjustAnnotationDirectory(int annotationDirectoryOffset) {
155         return annotationDirectoryOffsets.get(annotationDirectoryOffset);
156     }
157 
adjustStaticValues(int staticValuesOffset)158     public int adjustStaticValues(int staticValuesOffset) {
159         return staticValuesOffsets.get(staticValuesOffset);
160     }
161 
adjust(MethodId methodId)162     public MethodId adjust(MethodId methodId) {
163         return new MethodId(target,
164                 adjustType(methodId.getDeclaringClassIndex()),
165                 adjustProto(methodId.getProtoIndex()),
166                 adjustString(methodId.getNameIndex()));
167     }
168 
adjust(FieldId fieldId)169     public FieldId adjust(FieldId fieldId) {
170         return new FieldId(target,
171                 adjustType(fieldId.getDeclaringClassIndex()),
172                 adjustType(fieldId.getTypeIndex()),
173                 adjustString(fieldId.getNameIndex()));
174 
175     }
176 
adjust(ProtoId protoId)177     public ProtoId adjust(ProtoId protoId) {
178         return new ProtoId(target,
179                 adjustString(protoId.getShortyIndex()),
180                 adjustType(protoId.getReturnTypeIndex()),
181                 adjustTypeListOffset(protoId.getParametersOffset()));
182     }
183 
adjust(ClassDef classDef)184     public ClassDef adjust(ClassDef classDef) {
185         return new ClassDef(target, classDef.getOffset(), adjustType(classDef.getTypeIndex()),
186                 classDef.getAccessFlags(), adjustType(classDef.getSupertypeIndex()),
187                 adjustTypeListOffset(classDef.getInterfacesOffset()), classDef.getSourceFileIndex(),
188                 classDef.getAnnotationsOffset(), classDef.getClassDataOffset(),
189                 classDef.getStaticValuesOffset());
190     }
191 
adjust(SortableType sortableType)192     public SortableType adjust(SortableType sortableType) {
193         return new SortableType(sortableType.getBuffer(), adjust(sortableType.getClassDef()));
194     }
195 
adjustEncodedValue(EncodedValue encodedValue)196     public EncodedValue adjustEncodedValue(EncodedValue encodedValue) {
197         ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(32);
198         new EncodedValueTransformer(encodedValue, out).readValue();
199         return new EncodedValue(out.toByteArray());
200     }
201 
adjustEncodedArray(EncodedValue encodedArray)202     public EncodedValue adjustEncodedArray(EncodedValue encodedArray) {
203         ByteArrayAnnotatedOutput out = new ByteArrayAnnotatedOutput(32);
204         new EncodedValueTransformer(encodedArray, out).readArray();
205         return new EncodedValue(out.toByteArray());
206     }
207 
adjust(Annotation annotation)208     public Annotation adjust(Annotation annotation) {
209         int[] names = annotation.getNames().clone();
210         EncodedValue[] values = annotation.getValues().clone();
211         for (int i = 0; i < names.length; i++) {
212             names[i] = adjustString(names[i]);
213             values[i] = adjustEncodedValue(values[i]);
214         }
215         return new Annotation(target, annotation.getVisibility(),
216                 adjustType(annotation.getTypeIndex()), names, values);
217     }
218 
219     /**
220      * Adjust an encoded value or array.
221      */
222     private final class EncodedValueTransformer extends EncodedValueReader {
223         private final ByteOutput out;
224 
EncodedValueTransformer(EncodedValue encodedValue, ByteOutput out)225         public EncodedValueTransformer(EncodedValue encodedValue, ByteOutput out) {
226             super(encodedValue);
227             this.out = out;
228         }
229 
visitArray(int size)230         protected void visitArray(int size) {
231             Leb128Utils.writeUnsignedLeb128(out, size);
232         }
233 
visitAnnotation(int typeIndex, int size)234         protected void visitAnnotation(int typeIndex, int size) {
235             Leb128Utils.writeUnsignedLeb128(out, adjustType(typeIndex));
236             Leb128Utils.writeUnsignedLeb128(out, size);
237         }
238 
visitAnnotationName(int index)239         protected void visitAnnotationName(int index) {
240             Leb128Utils.writeUnsignedLeb128(out, adjustString(index));
241         }
242 
visitPrimitive(int argAndType, int type, int arg, int size)243         protected void visitPrimitive(int argAndType, int type, int arg, int size) {
244             out.writeByte(argAndType);
245             copyBytes(in, out, size);
246         }
247 
visitString(int type, int index)248         protected void visitString(int type, int index) {
249             writeTypeAndSizeAndIndex(type, adjustString(index));
250         }
251 
visitType(int type, int index)252         protected void visitType(int type, int index) {
253             writeTypeAndSizeAndIndex(type, adjustType(index));
254         }
255 
visitField(int type, int index)256         protected void visitField(int type, int index) {
257             writeTypeAndSizeAndIndex(type, adjustField(index));
258         }
259 
visitMethod(int type, int index)260         protected void visitMethod(int type, int index) {
261             writeTypeAndSizeAndIndex(type, adjustMethod(index));
262         }
263 
visitArrayValue(int argAndType)264         protected void visitArrayValue(int argAndType) {
265             out.writeByte(argAndType);
266         }
267 
visitAnnotationValue(int argAndType)268         protected void visitAnnotationValue(int argAndType) {
269             out.writeByte(argAndType);
270         }
271 
visitEncodedBoolean(int argAndType)272         protected void visitEncodedBoolean(int argAndType) {
273             out.writeByte(argAndType);
274         }
275 
visitEncodedNull(int argAndType)276         protected void visitEncodedNull(int argAndType) {
277             out.writeByte(argAndType);
278         }
279 
writeTypeAndSizeAndIndex(int type, int index)280         private void writeTypeAndSizeAndIndex(int type, int index) {
281             int byteCount;
282             if (Unsigned.compare(index, 0xff) <= 0) {
283                 byteCount = 1;
284             } else if (Unsigned.compare(index, 0xffff) <= 0) {
285                 byteCount = 2;
286             } else if (Unsigned.compare(index, 0xffffff) <= 0) {
287                 byteCount = 3;
288             } else {
289                 byteCount = 4;
290             }
291             int argAndType = ((byteCount - 1) << 5) | type;
292             out.writeByte(argAndType);
293 
294             for (int i = 0; i < byteCount; i++) {
295                 out.writeByte(index & 0xff);
296                 index >>>= 8;
297             }
298         }
299 
copyBytes(ByteInput in, ByteOutput out, int size)300         private void copyBytes(ByteInput in, ByteOutput out, int size) {
301             for (int i = 0; i < size; i++) {
302                 out.writeByte(in.readByte());
303             }
304         }
305     }
306 }
307