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.Iterators; 37 import com.google.common.collect.Sets; 38 import org.jf.dexlib2.Opcodes; 39 import org.jf.dexlib2.ValueType; 40 import org.jf.dexlib2.iface.Annotation; 41 import org.jf.dexlib2.iface.MethodImplementation; 42 import org.jf.dexlib2.iface.MethodParameter; 43 import org.jf.dexlib2.iface.reference.*; 44 import org.jf.dexlib2.iface.value.*; 45 import org.jf.dexlib2.writer.DexWriter; 46 import org.jf.dexlib2.writer.builder.BuilderEncodedValues.*; 47 import org.jf.util.ExceptionWithContext; 48 49 import javax.annotation.Nonnull; 50 import javax.annotation.Nullable; 51 import java.io.IOException; 52 import java.util.Iterator; 53 import java.util.List; 54 import java.util.Set; 55 56 public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringReference, BuilderTypeReference, 57 BuilderTypeReference, BuilderProtoReference, BuilderFieldReference, BuilderMethodReference, 58 BuilderClassDef, BuilderAnnotation, BuilderAnnotationSet, BuilderTypeList, BuilderField, BuilderMethod, 59 BuilderEncodedValue, BuilderAnnotationElement> { 60 61 @Nonnull private final BuilderContext context; 62 makeDexBuilder()63 @Nonnull public static DexBuilder makeDexBuilder() { 64 BuilderContext context = new BuilderContext(); 65 return new DexBuilder(Opcodes.forApi(20), context); 66 } 67 68 @Deprecated 69 @Nonnull makeDexBuilder(int api)70 public static DexBuilder makeDexBuilder(int api) { 71 BuilderContext context = new BuilderContext(); 72 return new DexBuilder(Opcodes.forApi(api), context); 73 } 74 makeDexBuilder(@onnull Opcodes opcodes)75 @Nonnull public static DexBuilder makeDexBuilder(@Nonnull Opcodes opcodes) { 76 BuilderContext context = new BuilderContext(); 77 return new DexBuilder(opcodes, context); 78 } 79 DexBuilder(@onnull Opcodes opcodes, @Nonnull BuilderContext context)80 private DexBuilder(@Nonnull Opcodes opcodes, @Nonnull BuilderContext context) { 81 super(opcodes, context.stringPool, context.typePool, context.protoPool, 82 context.fieldPool, context.methodPool, context.classPool, context.typeListPool, context.annotationPool, 83 context.annotationSetPool); 84 this.context = context; 85 } 86 internField(@onnull String definingClass, @Nonnull String name, @Nonnull String type, int accessFlags, @Nullable EncodedValue initialValue, @Nonnull Set<? extends Annotation> annotations)87 @Nonnull public BuilderField internField(@Nonnull String definingClass, 88 @Nonnull String name, 89 @Nonnull String type, 90 int accessFlags, 91 @Nullable EncodedValue initialValue, 92 @Nonnull Set<? extends Annotation> annotations) { 93 return new BuilderField(context.fieldPool.internField(definingClass, name, type), 94 accessFlags, 95 context.internNullableEncodedValue(initialValue), 96 context.annotationSetPool.internAnnotationSet(annotations)); 97 } 98 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)99 @Nonnull public BuilderMethod internMethod(@Nonnull String definingClass, 100 @Nonnull String name, 101 @Nullable List<? extends MethodParameter> parameters, 102 @Nonnull String returnType, 103 int accessFlags, 104 @Nonnull Set<? extends Annotation> annotations, 105 @Nullable MethodImplementation methodImplementation) { 106 if (parameters == null) { 107 parameters = ImmutableList.of(); 108 } 109 return new BuilderMethod(context.methodPool.internMethod(definingClass, name, parameters, returnType), 110 internMethodParameters(parameters), 111 accessFlags, 112 context.annotationSetPool.internAnnotationSet(annotations), 113 methodImplementation); 114 } 115 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)116 @Nonnull public BuilderClassDef internClassDef(@Nonnull String type, 117 int accessFlags, 118 @Nullable String superclass, 119 @Nullable List<String> interfaces, 120 @Nullable String sourceFile, 121 @Nonnull Set<? extends Annotation> annotations, 122 @Nullable Iterable<? extends BuilderField> fields, 123 @Nullable Iterable<? extends BuilderMethod> methods) { 124 if (interfaces == null) { 125 interfaces = ImmutableList.of(); 126 } else { 127 Set<String> interfaces_copy = Sets.newHashSet(interfaces); 128 Iterator<String> interfaceIterator = interfaces.iterator(); 129 while (interfaceIterator.hasNext()) { 130 String iface = interfaceIterator.next(); 131 if (!interfaces_copy.contains(iface)) { 132 interfaceIterator.remove(); 133 } else { 134 interfaces_copy.remove(iface); 135 } 136 } 137 } 138 139 return context.classPool.internClass(new BuilderClassDef(context.typePool.internType(type), 140 accessFlags, 141 context.typePool.internNullableType(superclass), 142 context.typeListPool.internTypeList(interfaces), 143 context.stringPool.internNullableString(sourceFile), 144 context.annotationSetPool.internAnnotationSet(annotations), 145 fields, 146 methods)); 147 } 148 internStringReference(@onnull String string)149 @Nonnull public BuilderStringReference internStringReference(@Nonnull String string) { 150 return context.stringPool.internString(string); 151 } 152 internNullableStringReference(@ullable String string)153 @Nullable public BuilderStringReference internNullableStringReference(@Nullable String string) { 154 if (string != null) { 155 return internStringReference(string); 156 } 157 return null; 158 } 159 internTypeReference(@onnull String type)160 @Nonnull public BuilderTypeReference internTypeReference(@Nonnull String type) { 161 return context.typePool.internType(type); 162 } 163 internNullableTypeReference(@ullable String type)164 @Nullable public BuilderTypeReference internNullableTypeReference(@Nullable String type) { 165 if (type != null) { 166 return internTypeReference(type); 167 } 168 return null; 169 } 170 internFieldReference(@onnull FieldReference field)171 @Nonnull public BuilderFieldReference internFieldReference(@Nonnull FieldReference field) { 172 return context.fieldPool.internField(field); 173 } 174 internMethodReference(@onnull MethodReference method)175 @Nonnull public BuilderMethodReference internMethodReference(@Nonnull MethodReference method) { 176 return context.methodPool.internMethod(method); 177 } 178 internReference(@onnull Reference reference)179 @Nonnull public BuilderReference internReference(@Nonnull Reference reference) { 180 if (reference instanceof StringReference) { 181 return internStringReference(((StringReference)reference).getString()); 182 } 183 if (reference instanceof TypeReference) { 184 return internTypeReference(((TypeReference)reference).getType()); 185 } 186 if (reference instanceof MethodReference) { 187 return internMethodReference((MethodReference)reference); 188 } 189 if (reference instanceof FieldReference) { 190 return internFieldReference((FieldReference)reference); 191 } 192 throw new IllegalArgumentException("Could not determine type of reference"); 193 } 194 internMethodParameters( @ullable List<? extends MethodParameter> methodParameters)195 @Nonnull private List<BuilderMethodParameter> internMethodParameters( 196 @Nullable List<? extends MethodParameter> methodParameters) { 197 if (methodParameters == null) { 198 return ImmutableList.of(); 199 } 200 return ImmutableList.copyOf(Iterators.transform(methodParameters.iterator(), 201 new Function<MethodParameter, BuilderMethodParameter>() { 202 @Nullable @Override public BuilderMethodParameter apply(MethodParameter input) { 203 return internMethodParameter(input); 204 } 205 })); 206 } 207 208 @Nonnull private BuilderMethodParameter internMethodParameter(@Nonnull MethodParameter methodParameter) { 209 return new BuilderMethodParameter( 210 context.typePool.internType(methodParameter.getType()), 211 context.stringPool.internNullableString(methodParameter.getName()), 212 context.annotationSetPool.internAnnotationSet(methodParameter.getAnnotations())); 213 } 214 215 @Override protected void writeEncodedValue(@Nonnull InternalEncodedValueWriter writer, 216 @Nonnull BuilderEncodedValue encodedValue) throws IOException { 217 switch (encodedValue.getValueType()) { 218 case ValueType.ANNOTATION: 219 BuilderAnnotationEncodedValue annotationEncodedValue = (BuilderAnnotationEncodedValue)encodedValue; 220 writer.writeAnnotation(annotationEncodedValue.typeReference, annotationEncodedValue.elements); 221 break; 222 case ValueType.ARRAY: 223 BuilderArrayEncodedValue arrayEncodedValue = (BuilderArrayEncodedValue)encodedValue; 224 writer.writeArray(arrayEncodedValue.elements); 225 break; 226 case ValueType.BOOLEAN: 227 writer.writeBoolean(((BooleanEncodedValue)encodedValue).getValue()); 228 break; 229 case ValueType.BYTE: 230 writer.writeByte(((ByteEncodedValue)encodedValue).getValue()); 231 break; 232 case ValueType.CHAR: 233 writer.writeChar(((CharEncodedValue)encodedValue).getValue()); 234 break; 235 case ValueType.DOUBLE: 236 writer.writeDouble(((DoubleEncodedValue)encodedValue).getValue()); 237 break; 238 case ValueType.ENUM: 239 writer.writeEnum(((BuilderEnumEncodedValue)encodedValue).getValue()); 240 break; 241 case ValueType.FIELD: 242 writer.writeField(((BuilderFieldEncodedValue)encodedValue).fieldReference); 243 break; 244 case ValueType.FLOAT: 245 writer.writeFloat(((FloatEncodedValue)encodedValue).getValue()); 246 break; 247 case ValueType.INT: 248 writer.writeInt(((IntEncodedValue)encodedValue).getValue()); 249 break; 250 case ValueType.LONG: 251 writer.writeLong(((LongEncodedValue)encodedValue).getValue()); 252 break; 253 case ValueType.METHOD: 254 writer.writeMethod(((BuilderMethodEncodedValue)encodedValue).methodReference); 255 break; 256 case ValueType.NULL: 257 writer.writeNull(); 258 break; 259 case ValueType.SHORT: 260 writer.writeShort(((ShortEncodedValue)encodedValue).getValue()); 261 break; 262 case ValueType.STRING: 263 writer.writeString(((BuilderStringEncodedValue)encodedValue).stringReference); 264 break; 265 case ValueType.TYPE: 266 writer.writeType(((BuilderTypeEncodedValue)encodedValue).typeReference); 267 break; 268 default: 269 throw new ExceptionWithContext("Unrecognized value type: %d", encodedValue.getValueType()); 270 } 271 } 272 } 273