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 65 public DexBuilder(@Nonnull Opcodes opcodes) { 66 super(opcodes); 67 } 68 69 @Nonnull @Override protected SectionProvider getSectionProvider() { 70 return new DexBuilderSectionProvider(); 71 } 72 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 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 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 135 @Nonnull public BuilderStringReference internStringReference(@Nonnull String string) { 136 return stringSection.internString(string); 137 } 138 139 @Nullable public BuilderStringReference internNullableStringReference(@Nullable String string) { 140 if (string != null) { 141 return internStringReference(string); 142 } 143 return null; 144 } 145 146 @Nonnull public BuilderTypeReference internTypeReference(@Nonnull String type) { 147 return typeSection.internType(type); 148 } 149 150 @Nullable public BuilderTypeReference internNullableTypeReference(@Nullable String type) { 151 if (type != null) { 152 return internTypeReference(type); 153 } 154 return null; 155 } 156 157 @Nonnull public BuilderFieldReference internFieldReference(@Nonnull FieldReference field) { 158 return fieldSection.internField(field); 159 } 160 161 @Nonnull public BuilderMethodReference internMethodReference(@Nonnull MethodReference method) { 162 return methodSection.internMethod(method); 163 } 164 165 @Nonnull public BuilderMethodProtoReference internMethodProtoReference(@Nonnull MethodProtoReference methodProto) { 166 return protoSection.internMethodProto(methodProto); 167 } 168 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 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