diff --git a/dexlib/src/main/java/org/jf/dexlib/ClassDefItem.java b/dexlib/src/main/java/org/jf/dexlib/ClassDefItem.java index 4423a864..45b4f0d8 100644 --- a/dexlib/src/main/java/org/jf/dexlib/ClassDefItem.java +++ b/dexlib/src/main/java/org/jf/dexlib/ClassDefItem.java @@ -31,6 +31,9 @@ package org.jf.dexlib; import org.jf.dexlib.Util.Input; import org.jf.dexlib.Util.AnnotatedOutput; import org.jf.dexlib.Util.AccessFlags; +import org.jf.dexlib.Util.TypeUtils; +import org.jf.dexlib.EncodedValue.EncodedValue; +import org.jf.dexlib.EncodedValue.ArrayEncodedSubValue; import java.util.*; @@ -62,7 +65,11 @@ public class ClassDefItem extends Item { * @param sourceFile The main source file that this class is defined in, or null if not available * @param annotations The annotations for this class and its fields, methods and method parameters, or null if none * @param classData The ClassDataItem containing the method and field definitions for this class - * @param staticFieldInitializers The initial values for this class's static fields, or null if none + * @param staticFieldInitializers The initial values for this class's static fields, or null if none. The initial + * values should be in the same order as the static fields in the ClassDataItem. It can contain + * fewer items than static fields, in which case the remaining static fields will be initialized with a default + * value of null/0. The initial value for any fields that don't specifically have a value can be either the + * type-appropriate null/0 encoded value, or null. */ private ClassDefItem(DexFile dexFile, TypeIdItem classType, int accessFlags, TypeIdItem superType, TypeListItem implementedInterfaces, StringIdItem sourceFile, @@ -97,16 +104,28 @@ public class ClassDefItem extends Item { * @param sourceFile The main source file that this class is defined in, or null if not available * @param annotations The annotations for this class and its fields, methods and method parameters, or null if none * @param classData The ClassDataItem containing the method and field definitions for this class - * @param staticFieldInitializers The initial values for this class's static fields, or null if none + * @param staticFieldInitializers The initial values for this class's static fields, or null if none. The initial + * values should be in the same order as the fields in the staticFieldsstaticFieldInitializers. The static fields are needed in order to sort the initial values correctly * @return a ClassDefItem for the given values, and that has been interned into the given * DexFile */ public static ClassDefItem getInternedClassDefItem(DexFile dexFile, TypeIdItem classType, int accessFlags, TypeIdItem superType, TypeListItem implementedInterfaces, StringIdItem sourceFile, AnnotationDirectoryItem annotations, ClassDataItem classData, - EncodedArrayItem staticFieldInitializers) { + EncodedValue[] staticFieldInitializers, ClassDataItem.EncodedField[] staticFields) { + EncodedArrayItem encodedArrayItem = null; + if(!dexFile.getInplace() && staticFieldInitializers != null) { + encodedArrayItem = makeStaticFieldInitializersItem(dexFile, staticFieldInitializers, + staticFields); + } + ClassDefItem classDefItem = new ClassDefItem(dexFile, classType, accessFlags, superType, implementedInterfaces, - sourceFile, annotations, classData, staticFieldInitializers); + sourceFile, annotations, classData, encodedArrayItem); return dexFile.ClassDefsSection.intern(classDefItem); } @@ -286,6 +305,81 @@ public class ClassDefItem extends Item { unplacedClassDefsByType.remove(classDefItem.classType); } } + } + /** + * A helper method to sort the static field initializers and populate the default values as needed + * @param dexFile the DexFile + * @param staticFieldInitializers the initial values + * @param fields the fields that correspond to each initial value in staticFieldInitializers + * @return an interned EncodedArrayItem containing the static field initializers + */ + private static EncodedArrayItem makeStaticFieldInitializersItem(DexFile dexFile, + EncodedValue[] staticFieldInitializers, + ClassDataItem.EncodedField[] fields) { + class FieldAndValue { + public final EncodedValue value; + public final ClassDataItem.EncodedField field; + public FieldAndValue(ClassDataItem.EncodedField field, EncodedValue value) { + this.field = field; + this.value = value; + } + } + + if (staticFieldInitializers == null || staticFieldInitializers.length == 0) { + return null; + } + + int len = fields.length; + + FieldAndValue[] fieldAndValues = new FieldAndValue[len]; + + for (int i=0; i() { + public int compare(FieldAndValue a, FieldAndValue b) { + return a.field.compareTo(b.field); + } + }); + + int lastIndex = -1; + for (int i=0; i