• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013, Google Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 package org.jf.dexlib2.writer.builder;
33 
34 import com.google.common.base.Function;
35 import com.google.common.collect.ImmutableList;
36 import com.google.common.collect.ImmutableSet;
37 import com.google.common.collect.Iterators;
38 import com.google.common.collect.Sets;
39 import org.jf.dexlib2.Opcodes;
40 import org.jf.dexlib2.ValueType;
41 import org.jf.dexlib2.iface.Annotation;
42 import org.jf.dexlib2.iface.AnnotationElement;
43 import org.jf.dexlib2.iface.MethodImplementation;
44 import org.jf.dexlib2.iface.MethodParameter;
45 import org.jf.dexlib2.iface.reference.*;
46 import org.jf.dexlib2.iface.value.*;
47 import org.jf.dexlib2.writer.DexWriter;
48 import org.jf.dexlib2.writer.builder.BuilderEncodedValues.*;
49 import org.jf.util.ExceptionWithContext;
50 
51 import javax.annotation.Nonnull;
52 import javax.annotation.Nullable;
53 import java.io.IOException;
54 import java.util.Iterator;
55 import java.util.List;
56 import java.util.Set;
57 
58 public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringReference, BuilderTypeReference,
59         BuilderTypeReference, BuilderMethodProtoReference, BuilderFieldReference, BuilderMethodReference,
60         BuilderClassDef, BuilderAnnotation, BuilderAnnotationSet, BuilderTypeList, BuilderField, BuilderMethod,
61         BuilderEncodedValue, BuilderAnnotationElement, BuilderStringPool, BuilderTypePool, BuilderProtoPool,
62         BuilderFieldPool, BuilderMethodPool, BuilderClassPool, BuilderTypeListPool, BuilderAnnotationPool,
63         BuilderAnnotationSetPool> {
64 
DexBuilder(@onnull Opcodes opcodes)65     public DexBuilder(@Nonnull Opcodes opcodes) {
66         super(opcodes);
67     }
68 
getSectionProvider()69     @Nonnull @Override protected SectionProvider getSectionProvider() {
70         return new DexBuilderSectionProvider();
71     }
72 
internField(@onnull String definingClass, @Nonnull String name, @Nonnull String type, int accessFlags, @Nullable EncodedValue initialValue, @Nonnull Set<? extends Annotation> annotations)73     @Nonnull public BuilderField internField(@Nonnull String definingClass,
74                                              @Nonnull String name,
75                                              @Nonnull String type,
76                                              int accessFlags,
77                                              @Nullable EncodedValue initialValue,
78                                              @Nonnull Set<? extends Annotation> annotations) {
79         return new BuilderField(fieldSection.internField(definingClass, name, type),
80                 accessFlags,
81                 internNullableEncodedValue(initialValue),
82                 annotationSetSection.internAnnotationSet(annotations));
83     }
84 
internMethod(@onnull String definingClass, @Nonnull String name, @Nullable List<? extends MethodParameter> parameters, @Nonnull String returnType, int accessFlags, @Nonnull Set<? extends Annotation> annotations, @Nullable MethodImplementation methodImplementation)85     @Nonnull public BuilderMethod internMethod(@Nonnull String definingClass,
86                                                @Nonnull String name,
87                                                @Nullable List<? extends MethodParameter> parameters,
88                                                @Nonnull String returnType,
89                                                int accessFlags,
90                                                @Nonnull Set<? extends Annotation> annotations,
91                                                @Nullable MethodImplementation methodImplementation) {
92         if (parameters == null) {
93             parameters = ImmutableList.of();
94         }
95         return new BuilderMethod(methodSection.internMethod(definingClass, name, parameters, returnType),
96                 internMethodParameters(parameters),
97                 accessFlags,
98                 annotationSetSection.internAnnotationSet(annotations),
99                 methodImplementation);
100     }
101 
internClassDef(@onnull String type, int accessFlags, @Nullable String superclass, @Nullable List<String> interfaces, @Nullable String sourceFile, @Nonnull Set<? extends Annotation> annotations, @Nullable Iterable<? extends BuilderField> fields, @Nullable Iterable<? extends BuilderMethod> methods)102     @Nonnull public BuilderClassDef internClassDef(@Nonnull String type,
103                                                    int accessFlags,
104                                                    @Nullable String superclass,
105                                                    @Nullable List<String> interfaces,
106                                                    @Nullable String sourceFile,
107                                                    @Nonnull Set<? extends Annotation> annotations,
108                                                    @Nullable Iterable<? extends BuilderField> fields,
109                                                    @Nullable Iterable<? extends BuilderMethod> methods) {
110         if (interfaces == null) {
111             interfaces = ImmutableList.of();
112         } else {
113             Set<String> interfaces_copy = Sets.newHashSet(interfaces);
114             Iterator<String> interfaceIterator = interfaces.iterator();
115             while (interfaceIterator.hasNext()) {
116                 String iface = interfaceIterator.next();
117                 if (!interfaces_copy.contains(iface)) {
118                     interfaceIterator.remove();
119                 } else {
120                     interfaces_copy.remove(iface);
121                 }
122             }
123         }
124 
125         return classSection.internClass(new BuilderClassDef(typeSection.internType(type),
126                 accessFlags,
127                 typeSection.internNullableType(superclass),
128                 typeListSection.internTypeList(interfaces),
129                 stringSection.internNullableString(sourceFile),
130                 annotationSetSection.internAnnotationSet(annotations),
131                 fields,
132                 methods));
133     }
134 
internStringReference(@onnull String string)135     @Nonnull public BuilderStringReference internStringReference(@Nonnull String string) {
136         return stringSection.internString(string);
137     }
138 
internNullableStringReference(@ullable String string)139     @Nullable public BuilderStringReference internNullableStringReference(@Nullable String string) {
140         if (string != null) {
141             return internStringReference(string);
142         }
143         return null;
144     }
145 
internTypeReference(@onnull String type)146     @Nonnull public BuilderTypeReference internTypeReference(@Nonnull String type) {
147         return typeSection.internType(type);
148     }
149 
internNullableTypeReference(@ullable String type)150     @Nullable public BuilderTypeReference internNullableTypeReference(@Nullable String type) {
151         if (type != null) {
152             return internTypeReference(type);
153         }
154         return null;
155     }
156 
internFieldReference(@onnull FieldReference field)157     @Nonnull public BuilderFieldReference internFieldReference(@Nonnull FieldReference field) {
158         return fieldSection.internField(field);
159     }
160 
internMethodReference(@onnull MethodReference method)161     @Nonnull public BuilderMethodReference internMethodReference(@Nonnull MethodReference method) {
162         return methodSection.internMethod(method);
163     }
164 
internMethodProtoReference(@onnull MethodProtoReference methodProto)165     @Nonnull public BuilderMethodProtoReference internMethodProtoReference(@Nonnull MethodProtoReference methodProto) {
166         return protoSection.internMethodProto(methodProto);
167     }
168 
internReference(@onnull Reference reference)169     @Nonnull public BuilderReference internReference(@Nonnull Reference reference) {
170         if (reference instanceof StringReference) {
171             return internStringReference(((StringReference)reference).getString());
172         }
173         if (reference instanceof TypeReference) {
174             return internTypeReference(((TypeReference)reference).getType());
175         }
176         if (reference instanceof MethodReference) {
177             return internMethodReference((MethodReference)reference);
178         }
179         if (reference instanceof FieldReference) {
180             return internFieldReference((FieldReference)reference);
181         }
182         if (reference instanceof MethodProtoReference) {
183             return internMethodProtoReference((MethodProtoReference) reference);
184         }
185         throw new IllegalArgumentException("Could not determine type of reference");
186     }
187 
internMethodParameters( @ullable List<? extends MethodParameter> methodParameters)188     @Nonnull private List<BuilderMethodParameter> internMethodParameters(
189             @Nullable List<? extends MethodParameter> methodParameters) {
190         if (methodParameters == null) {
191             return ImmutableList.of();
192         }
193         return ImmutableList.copyOf(Iterators.transform(methodParameters.iterator(),
194                 new Function<MethodParameter, BuilderMethodParameter>() {
195                     @Nullable @Override public BuilderMethodParameter apply(MethodParameter input) {
196                         return internMethodParameter(input);
197                     }
198                 }));
199     }
200 
201     @Nonnull private BuilderMethodParameter internMethodParameter(@Nonnull MethodParameter methodParameter) {
202         return new BuilderMethodParameter(
203                 typeSection.internType(methodParameter.getType()),
204                 stringSection.internNullableString(methodParameter.getName()),
205                 annotationSetSection.internAnnotationSet(methodParameter.getAnnotations()));
206     }
207 
208     @Override protected void writeEncodedValue(@Nonnull InternalEncodedValueWriter writer,
209                                                @Nonnull BuilderEncodedValue encodedValue) throws IOException {
210         switch (encodedValue.getValueType()) {
211             case ValueType.ANNOTATION:
212                 BuilderAnnotationEncodedValue annotationEncodedValue = (BuilderAnnotationEncodedValue)encodedValue;
213                 writer.writeAnnotation(annotationEncodedValue.typeReference, annotationEncodedValue.elements);
214                 break;
215             case ValueType.ARRAY:
216                 BuilderArrayEncodedValue arrayEncodedValue = (BuilderArrayEncodedValue)encodedValue;
217                 writer.writeArray(arrayEncodedValue.elements);
218                 break;
219             case ValueType.BOOLEAN:
220                 writer.writeBoolean(((BooleanEncodedValue)encodedValue).getValue());
221                 break;
222             case ValueType.BYTE:
223                 writer.writeByte(((ByteEncodedValue)encodedValue).getValue());
224                 break;
225             case ValueType.CHAR:
226                 writer.writeChar(((CharEncodedValue)encodedValue).getValue());
227                 break;
228             case ValueType.DOUBLE:
229                 writer.writeDouble(((DoubleEncodedValue)encodedValue).getValue());
230                 break;
231             case ValueType.ENUM:
232                 writer.writeEnum(((BuilderEnumEncodedValue)encodedValue).getValue());
233                 break;
234             case ValueType.FIELD:
235                 writer.writeField(((BuilderFieldEncodedValue)encodedValue).fieldReference);
236                 break;
237             case ValueType.FLOAT:
238                 writer.writeFloat(((FloatEncodedValue)encodedValue).getValue());
239                 break;
240             case ValueType.INT:
241                 writer.writeInt(((IntEncodedValue)encodedValue).getValue());
242                 break;
243             case ValueType.LONG:
244                 writer.writeLong(((LongEncodedValue)encodedValue).getValue());
245                 break;
246             case ValueType.METHOD:
247                 writer.writeMethod(((BuilderMethodEncodedValue)encodedValue).methodReference);
248                 break;
249             case ValueType.NULL:
250                 writer.writeNull();
251                 break;
252             case ValueType.SHORT:
253                 writer.writeShort(((ShortEncodedValue)encodedValue).getValue());
254                 break;
255             case ValueType.STRING:
256                 writer.writeString(((BuilderStringEncodedValue)encodedValue).stringReference);
257                 break;
258             case ValueType.TYPE:
259                 writer.writeType(((BuilderTypeEncodedValue)encodedValue).typeReference);
260                 break;
261             default:
262                 throw new ExceptionWithContext("Unrecognized value type: %d", encodedValue.getValueType());
263         }
264     }
265 
266     @Nonnull Set<? extends BuilderAnnotationElement> internAnnotationElements(
267             @Nonnull Set<? extends AnnotationElement> elements) {
268         return ImmutableSet.copyOf(
269                 Iterators.transform(elements.iterator(),
270                         new Function<AnnotationElement, BuilderAnnotationElement>() {
271                             @Nullable @Override
272                             public BuilderAnnotationElement apply(AnnotationElement input) {
273                                 return internAnnotationElement(input);
274                             }
275                         }));
276     }
277 
278     @Nonnull private BuilderAnnotationElement internAnnotationElement(@Nonnull AnnotationElement annotationElement) {
279         return new BuilderAnnotationElement(stringSection.internString(annotationElement.getName()),
280                 internEncodedValue(annotationElement.getValue()));
281     }
282 
283     @Nullable BuilderEncodedValue internNullableEncodedValue(@Nullable EncodedValue encodedValue) {
284         if (encodedValue == null) {
285             return null;
286         }
287         return internEncodedValue(encodedValue);
288     }
289 
290     @Nonnull private BuilderEncodedValue internEncodedValue(@Nonnull EncodedValue encodedValue) {
291         switch (encodedValue.getValueType()) {
292             case ValueType.ANNOTATION:
293                 return internAnnotationEncodedValue((AnnotationEncodedValue)encodedValue);
294             case ValueType.ARRAY:
295                 return internArrayEncodedValue((ArrayEncodedValue)encodedValue);
296             case ValueType.BOOLEAN:
297                 boolean value = ((BooleanEncodedValue)encodedValue).getValue();
298                 return value?BuilderBooleanEncodedValue.TRUE_VALUE:BuilderBooleanEncodedValue.FALSE_VALUE;
299             case ValueType.BYTE:
300                 return new BuilderByteEncodedValue(((ByteEncodedValue)encodedValue).getValue());
301             case ValueType.CHAR:
302                 return new BuilderCharEncodedValue(((CharEncodedValue)encodedValue).getValue());
303             case ValueType.DOUBLE:
304                 return new BuilderDoubleEncodedValue(((DoubleEncodedValue)encodedValue).getValue());
305             case ValueType.ENUM:
306                 return internEnumEncodedValue((EnumEncodedValue)encodedValue);
307             case ValueType.FIELD:
308                 return internFieldEncodedValue((FieldEncodedValue)encodedValue);
309             case ValueType.FLOAT:
310                 return new BuilderFloatEncodedValue(((FloatEncodedValue)encodedValue).getValue());
311             case ValueType.INT:
312                 return new BuilderIntEncodedValue(((IntEncodedValue)encodedValue).getValue());
313             case ValueType.LONG:
314                 return new BuilderLongEncodedValue(((LongEncodedValue)encodedValue).getValue());
315             case ValueType.METHOD:
316                 return internMethodEncodedValue((MethodEncodedValue)encodedValue);
317             case ValueType.NULL:
318                 return BuilderNullEncodedValue.INSTANCE;
319             case ValueType.SHORT:
320                 return new BuilderShortEncodedValue(((ShortEncodedValue)encodedValue).getValue());
321             case ValueType.STRING:
322                 return internStringEncodedValue((StringEncodedValue)encodedValue);
323             case ValueType.TYPE:
324                 return internTypeEncodedValue((TypeEncodedValue)encodedValue);
325             default:
326                 throw new ExceptionWithContext("Unexpected encoded value type: %d", encodedValue.getValueType());
327         }
328     }
329 
330     @Nonnull private BuilderAnnotationEncodedValue internAnnotationEncodedValue(@Nonnull AnnotationEncodedValue value) {
331         return new BuilderAnnotationEncodedValue(
332                 typeSection.internType(value.getType()),
333                 internAnnotationElements(value.getElements()));
334     }
335 
336     @Nonnull private BuilderArrayEncodedValue internArrayEncodedValue(@Nonnull ArrayEncodedValue value) {
337         return new BuilderArrayEncodedValue(
338                 ImmutableList.copyOf(
339                         Iterators.transform(value.getValue().iterator(),
340                                 new Function<EncodedValue, BuilderEncodedValue>() {
341                                     @Nullable @Override public BuilderEncodedValue apply(EncodedValue input) {
342                                         return internEncodedValue(input);
343                                     }
344                                 })));
345     }
346 
347     @Nonnull private BuilderEnumEncodedValue internEnumEncodedValue(@Nonnull EnumEncodedValue value) {
348         return new BuilderEnumEncodedValue(fieldSection.internField(value.getValue()));
349     }
350 
351     @Nonnull private BuilderFieldEncodedValue internFieldEncodedValue(@Nonnull FieldEncodedValue value) {
352         return new BuilderFieldEncodedValue(fieldSection.internField(value.getValue()));
353     }
354 
355     @Nonnull private BuilderMethodEncodedValue internMethodEncodedValue(@Nonnull MethodEncodedValue value) {
356         return new BuilderMethodEncodedValue(methodSection.internMethod(value.getValue()));
357     }
358 
359     @Nonnull private BuilderStringEncodedValue internStringEncodedValue(@Nonnull StringEncodedValue string) {
360         return new BuilderStringEncodedValue(stringSection.internString(string.getValue()));
361     }
362 
363     @Nonnull private BuilderTypeEncodedValue internTypeEncodedValue(@Nonnull TypeEncodedValue type) {
364         return new BuilderTypeEncodedValue(typeSection.internType(type.getValue()));
365     }
366 
367     protected class DexBuilderSectionProvider extends SectionProvider {
368         @Nonnull @Override public BuilderStringPool getStringSection() {
369             return new BuilderStringPool();
370         }
371 
372         @Nonnull @Override public BuilderTypePool getTypeSection() {
373             return new BuilderTypePool(DexBuilder.this);
374         }
375 
376         @Nonnull @Override public BuilderProtoPool getProtoSection() {
377             return new BuilderProtoPool(DexBuilder.this);
378         }
379 
380         @Nonnull @Override public BuilderFieldPool getFieldSection() {
381             return new BuilderFieldPool(DexBuilder.this);
382         }
383 
384         @Nonnull @Override public BuilderMethodPool getMethodSection() {
385             return new BuilderMethodPool(DexBuilder.this);
386         }
387 
388         @Nonnull @Override public BuilderClassPool getClassSection() {
389             return new BuilderClassPool(DexBuilder.this);
390         }
391 
392         @Nonnull @Override public BuilderTypeListPool getTypeListSection() {
393             return new BuilderTypeListPool(DexBuilder.this);
394         }
395 
396         @Nonnull @Override public BuilderAnnotationPool getAnnotationSection() {
397             return new BuilderAnnotationPool(DexBuilder.this);
398         }
399 
400         @Nonnull @Override public BuilderAnnotationSetPool getAnnotationSetSection() {
401             return new BuilderAnnotationSetPool(DexBuilder.this);
402         }
403     }
404 }
405