mirror of
https://github.com/revanced/smali.git
synced 2025-05-29 12:20:11 +02:00
- started writing javadoc documentation
- cleanup of DexFile, and related refactoring git-svn-id: https://smali.googlecode.com/svn/trunk@211 55b6fa8a-2a1e-11de-a435-ffa8d773f76a
This commit is contained in:
parent
d166b746b9
commit
281b510a9c
@ -10,6 +10,14 @@
|
|||||||
<artifactId>smali-pom</artifactId>
|
<artifactId>smali-pom</artifactId>
|
||||||
<version>0.91-SNAPSHOT</version>
|
<version>0.91-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
<reporting>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-javadoc-plugin</artifactId>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</reporting>
|
||||||
<dependencies>
|
<dependencies>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>junit</groupId>
|
<groupId>junit</groupId>
|
||||||
|
@ -54,7 +54,7 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
|
|||||||
private ClassDefItem parent = null;
|
private ClassDefItem parent = null;
|
||||||
|
|
||||||
protected AnnotationDirectoryItem(final DexFile dexFile, int offset) {
|
protected AnnotationDirectoryItem(final DexFile dexFile, int offset) {
|
||||||
super(offset);
|
super(dexFile, offset);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
classAnnotationsReferenceField = new OffsettedItemReference<AnnotationSetItem>(
|
classAnnotationsReferenceField = new OffsettedItemReference<AnnotationSetItem>(
|
||||||
|
@ -35,7 +35,7 @@ public class AnnotationItem extends OffsettedItem<AnnotationItem> {
|
|||||||
private final AnnotationEncodedValueSubField annotationField;
|
private final AnnotationEncodedValueSubField annotationField;
|
||||||
|
|
||||||
public AnnotationItem(DexFile dexFile, int offset) {
|
public AnnotationItem(DexFile dexFile, int offset) {
|
||||||
super(offset);
|
super(dexFile, offset);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
visibilityField = new ByteField("visibility"),
|
visibilityField = new ByteField("visibility"),
|
||||||
@ -45,7 +45,7 @@ public class AnnotationItem extends OffsettedItem<AnnotationItem> {
|
|||||||
|
|
||||||
public AnnotationItem(DexFile dexFile, AnnotationVisibility visibility,
|
public AnnotationItem(DexFile dexFile, AnnotationVisibility visibility,
|
||||||
AnnotationEncodedValueSubField annotation) {
|
AnnotationEncodedValueSubField annotation) {
|
||||||
super(-1);
|
super(dexFile, -1);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
this.visibilityField = new ByteField(visibility.value, "visibility"),
|
this.visibilityField = new ByteField(visibility.value, "visibility"),
|
||||||
|
@ -39,7 +39,7 @@ public class AnnotationSetItem extends OffsettedItem<AnnotationSetItem> {
|
|||||||
private final FieldListField<OffsettedItemReference<AnnotationItem>> annotationsListField;
|
private final FieldListField<OffsettedItemReference<AnnotationItem>> annotationsListField;
|
||||||
|
|
||||||
public AnnotationSetItem(final DexFile dexFile, int offset) {
|
public AnnotationSetItem(final DexFile dexFile, int offset) {
|
||||||
super(offset);
|
super(dexFile, offset);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
annotationCountField = new ListSizeField(annotationReferences, new IntegerField("size")),
|
annotationCountField = new ListSizeField(annotationReferences, new IntegerField("size")),
|
||||||
|
@ -39,7 +39,7 @@ public class AnnotationSetRefList extends OffsettedItem<AnnotationSetRefList> {
|
|||||||
private final FieldListField<OffsettedItemReference<AnnotationSetItem>> annotationSetsListField;
|
private final FieldListField<OffsettedItemReference<AnnotationSetItem>> annotationSetsListField;
|
||||||
|
|
||||||
public AnnotationSetRefList(final DexFile dexFile, int offset) {
|
public AnnotationSetRefList(final DexFile dexFile, int offset) {
|
||||||
super(offset);
|
super(dexFile, offset);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
annotationSetCountField = new ListSizeField(annotationSetReferences, new IntegerField("size")),
|
annotationSetCountField = new ListSizeField(annotationSetReferences, new IntegerField("size")),
|
||||||
|
@ -52,7 +52,7 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
|
|||||||
private ClassDefItem parent = null;
|
private ClassDefItem parent = null;
|
||||||
|
|
||||||
public ClassDataItem(final DexFile dexFile, int offset) {
|
public ClassDataItem(final DexFile dexFile, int offset) {
|
||||||
super(offset);
|
super(dexFile, offset);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
staticFieldsCountField = new ListSizeField(staticFieldList,
|
staticFieldsCountField = new ListSizeField(staticFieldList,
|
||||||
|
@ -50,7 +50,7 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
|||||||
private final DexFile dexFile;
|
private final DexFile dexFile;
|
||||||
|
|
||||||
public ClassDefItem(DexFile dexFile, int index) {
|
public ClassDefItem(DexFile dexFile, int index) {
|
||||||
super(index);
|
super(dexFile, index);
|
||||||
|
|
||||||
this.dexFile = dexFile;
|
this.dexFile = dexFile;
|
||||||
|
|
||||||
|
@ -161,16 +161,16 @@ public abstract class Instruction {
|
|||||||
if (referencedItem != null) {
|
if (referencedItem != null) {
|
||||||
switch (opcode.referenceType) {
|
switch (opcode.referenceType) {
|
||||||
case string:
|
case string:
|
||||||
clone.referencedItem = dexFile.StringIdsSection.intern(dexFile, (StringIdItem)referencedItem);
|
clone.referencedItem = dexFile.StringIdsSection.intern((StringIdItem)referencedItem);
|
||||||
break;
|
break;
|
||||||
case type:
|
case type:
|
||||||
clone.referencedItem = dexFile.TypeIdsSection.intern(dexFile, (TypeIdItem)referencedItem);
|
clone.referencedItem = dexFile.TypeIdsSection.intern((TypeIdItem)referencedItem);
|
||||||
break;
|
break;
|
||||||
case field:
|
case field:
|
||||||
clone.referencedItem = dexFile.FieldIdsSection.intern(dexFile, (FieldIdItem)referencedItem);
|
clone.referencedItem = dexFile.FieldIdsSection.intern((FieldIdItem)referencedItem);
|
||||||
break;
|
break;
|
||||||
case method:
|
case method:
|
||||||
clone.referencedItem = dexFile.MethodIdsSection.intern(dexFile, (MethodIdItem)referencedItem);
|
clone.referencedItem = dexFile.MethodIdsSection.intern((MethodIdItem)referencedItem);
|
||||||
break;
|
break;
|
||||||
case none:
|
case none:
|
||||||
break;
|
break;
|
||||||
|
@ -57,7 +57,7 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
|||||||
private MethodIdItem parent = null;
|
private MethodIdItem parent = null;
|
||||||
|
|
||||||
public CodeItem(final DexFile dexFile, int offset) {
|
public CodeItem(final DexFile dexFile, int offset) {
|
||||||
super(offset);
|
super(dexFile, offset);
|
||||||
|
|
||||||
instructionList = new ArrayList<InstructionField>();
|
instructionList = new ArrayList<InstructionField>();
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ public abstract class DebugInstructionFactory {
|
|||||||
case 0x05:
|
case 0x05:
|
||||||
return new EndLocal();
|
return new EndLocal();
|
||||||
case 0x06:
|
case 0x06:
|
||||||
return new RestartLocal(dexFile.isForDumping());
|
return new RestartLocal(dexFile);
|
||||||
case 0x07:
|
case 0x07:
|
||||||
return new SetPrologueEnd();
|
return new SetPrologueEnd();
|
||||||
case 0x08:
|
case 0x08:
|
||||||
|
@ -34,18 +34,23 @@ public class RestartLocal extends CompositeField<RestartLocal> implements DebugI
|
|||||||
private final ByteField opcode;
|
private final ByteField opcode;
|
||||||
private final Leb128Field registerNumber;
|
private final Leb128Field registerNumber;
|
||||||
|
|
||||||
public RestartLocal(boolean forDumping) {
|
public RestartLocal(DexFile dexFile) {
|
||||||
super("DBG_RESTART_LOCAL");
|
super("DBG_RESTART_LOCAL");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
opcode = new ByteField((byte)0x06, "opcode"),
|
opcode = new ByteField((byte)0x06, "opcode"),
|
||||||
registerNumber = forDumping?new Leb128Field.PossiblySignedLeb128Field("register_num"):
|
registerNumber = dexFile.getPreserveSignedRegisters()?new Leb128Field.PossiblySignedLeb128Field("register_num"):
|
||||||
new Leb128Field("register_num")
|
new Leb128Field("register_num")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public RestartLocal(int registerNumber) {
|
public RestartLocal(int registerNumber) {
|
||||||
this(false);
|
super("DBG_RESTART_LOCAL");
|
||||||
this.registerNumber.cacheValue(registerNumber);
|
fields = new Field[] {
|
||||||
|
this.opcode = new ByteField((byte)0x06, "opcode"),
|
||||||
|
this.registerNumber = new Leb128Field(registerNumber, "register_num")
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte getOpcode() {
|
public byte getOpcode() {
|
||||||
|
@ -40,7 +40,7 @@ public class StartLocal extends CompositeField<StartLocal> implements DebugInstr
|
|||||||
super("DBG_START_LOCAL");
|
super("DBG_START_LOCAL");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
opcodeField = new ByteField((byte)0x03, "opcode"),
|
opcodeField = new ByteField((byte)0x03, "opcode"),
|
||||||
registerNumber = dexFile.isForDumping()?new Leb128Field.PossiblySignedLeb128Field("register_num"):
|
registerNumber = dexFile.getPreserveSignedRegisters()?new Leb128Field.PossiblySignedLeb128Field("register_num"):
|
||||||
new Leb128Field("register_num"),
|
new Leb128Field("register_num"),
|
||||||
localName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
localName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||||
new Leb128p1Field(null), "name_idx"),
|
new Leb128p1Field(null), "name_idx"),
|
||||||
|
@ -41,7 +41,7 @@ public class StartLocalExtended extends CompositeField<StartLocalExtended> imple
|
|||||||
super("DBG_START_LOCAL_EXTENDED");
|
super("DBG_START_LOCAL_EXTENDED");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
opcodeField = new ByteField((byte)0x04, "opcode"),
|
opcodeField = new ByteField((byte)0x04, "opcode"),
|
||||||
registerNumber = dexFile.isForDumping()?new Leb128Field.PossiblySignedLeb128Field("register_num"):
|
registerNumber = dexFile.getPreserveSignedRegisters()?new Leb128Field.PossiblySignedLeb128Field("register_num"):
|
||||||
new Leb128Field("register_num"),
|
new Leb128Field("register_num"),
|
||||||
localName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
localName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||||
new Leb128p1Field(null), "name_idx"),
|
new Leb128p1Field(null), "name_idx"),
|
||||||
|
@ -52,7 +52,7 @@ public class DebugInfoItem extends OffsettedItem<DebugInfoItem> {
|
|||||||
private CodeItem parent = null;
|
private CodeItem parent = null;
|
||||||
|
|
||||||
public DebugInfoItem(final DexFile dexFile, int offset) {
|
public DebugInfoItem(final DexFile dexFile, int offset) {
|
||||||
super(offset);
|
super(dexFile, offset);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
lineStartField = new Leb128Field("line_start"),
|
lineStartField = new Leb128Field("line_start"),
|
||||||
|
@ -38,22 +38,140 @@ import java.security.DigestException;
|
|||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import java.util.zip.Adler32;
|
import java.util.zip.Adler32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h3>Main use cases</h3>
|
||||||
|
*
|
||||||
|
* <p>These are the main use cases that drove the design of this library</p>
|
||||||
|
*
|
||||||
|
* <ol>
|
||||||
|
* <li><p><b>Annotate an existing dex file</b> - In this case, the intent is to document the structure of
|
||||||
|
* an existing dex file. We want to be able to read in the dex file, and then write out a dex file
|
||||||
|
* that is exactly the same (while adding annotation information to an AnnotatedOutput object)</p></li>
|
||||||
|
*
|
||||||
|
* <li><p><b>Canonicalize an existing dex file</b> - In this case, the intent is to rewrite an existing dex file
|
||||||
|
* so that it is in a canonical form. There is a certain amount of leeway in how various types of
|
||||||
|
* tems in a dex file are ordered or represented. It is sometimes useful to be able to easily
|
||||||
|
* compare a disassebled and reassembled dex file with the original dex file. If both dex-files are
|
||||||
|
* written canonically, they "should" match exactly, barring any explicit changes to the reassembled
|
||||||
|
* file.</p>
|
||||||
|
*
|
||||||
|
* <p>Currently, there are a couple of pieces of information that probably won't match exactly
|
||||||
|
* <ul>
|
||||||
|
* <li>the order of exception handlers in the <code>EncodedCatchHandlerList</code> for a method</li>
|
||||||
|
* <li>the ordering of some of the debug info in the <code>{@link DebugInfoItem}</code> for a method</li>
|
||||||
|
* </ul></p>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* <p>Note that the above discrepancies should typically only be "intra-item" differences. They
|
||||||
|
* shouldn't change the size of the item, or affect how anything else is placed or laid out</p></li>
|
||||||
|
*
|
||||||
|
* <li><p><b>Creating a dex file from scratch</b> - In this case, a blank dex file is created and then classes
|
||||||
|
* are added to it incrementally by calling the {@link Section#intern intern} method of
|
||||||
|
* {@link DexFile#ClassDefsSection}, which will add all the information necessary to represent the given
|
||||||
|
* class. For example, when assembling a dex file from a set of assembly text files.</p>
|
||||||
|
*
|
||||||
|
* <p>In this case, we can choose to write the dex file in a canonical form or not. It is somewhat
|
||||||
|
* slower to write it in a canonical format, due to the extra sorting and calculations that are
|
||||||
|
* required.</p></li>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* <li><p><b>Reading in the dex file</b> - In this case, the intent is to read in a dex file and expose all the
|
||||||
|
* data to the calling application. For example, when disassembling a dex file into a text based
|
||||||
|
* assembly format, or doing other misc processing of the dex file.</p></li>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* <h3>Other use cases</h3>
|
||||||
|
*
|
||||||
|
* <p>These are other use cases that are possible, but did not drive the design of the library.
|
||||||
|
* No effort was made to test these use cases or ensure that they work. Some of these could
|
||||||
|
* probably be better achieved with a disassemble - modify - reassemble type process, using
|
||||||
|
* smali/baksmali or another assembler/disassembler pair that are compatible with each other</p>
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>deleting classes/methods/etc. from a dex file</li>
|
||||||
|
* <li>merging 2 dex files</li>
|
||||||
|
* <li>splitting a dex file</li>
|
||||||
|
* <li>moving classes from 1 dex file to another</li>
|
||||||
|
* <li>removing the debug information from a dex file</li>
|
||||||
|
* <li>obfustication of a dex file</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
public class DexFile
|
public class DexFile
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* A mapping from ItemType to the section that contains items of the given type
|
||||||
|
*/
|
||||||
private final HashMap<ItemType, Section> sectionsByType;
|
private final HashMap<ItemType, Section> sectionsByType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ordered lists of the indexed and offsetted sections. The order of these lists specifies the order
|
||||||
|
* that the sections will be written in
|
||||||
|
*/
|
||||||
private final IndexedSection[] indexedSections;
|
private final IndexedSection[] indexedSections;
|
||||||
private final OffsettedSection[] offsettedSections;
|
private final OffsettedSection[] offsettedSections;
|
||||||
private int fileSize;
|
|
||||||
private int dataOffset;
|
|
||||||
private int dataSize;
|
|
||||||
private boolean forDumping;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dalvik had a bug where it wrote the registers for certain types of debug info in a signed leb
|
||||||
|
* format, instead of an unsigned leb format. There are no negative registers of course, but
|
||||||
|
* certain positive values have a different encoding depending on whether they are encoded as
|
||||||
|
* an unsigned leb128 or a signed leb128. Specifically, the signed leb128 is 1 byte longer in some cases.
|
||||||
|
*
|
||||||
|
* This determine whether we should keep any signed registers as signed, or force all register to
|
||||||
|
* unsigned. By default we don't keep track of whether they were signed or not, and write them back
|
||||||
|
* out as unsigned. This option only has an effect when reading an existing dex file. It has no
|
||||||
|
* effect when a dex file is created from scratch
|
||||||
|
*
|
||||||
|
* The 2 main use-cases in play are
|
||||||
|
* 1. Annotate an existing dex file - In this case, preserveSignedRegisters should be false, so that we keep
|
||||||
|
* track of any signed registers and write them back out as signed Leb128 values.
|
||||||
|
*
|
||||||
|
* 2. Canonicalize an existing dex file - In this case, fixRegisters should be true, so that all
|
||||||
|
* registers in the debug info are written as unsigned Leb128 values regardless of how they were
|
||||||
|
* originally encoded
|
||||||
|
*/
|
||||||
|
private final boolean preserveSignedRegisters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When true, this prevents any sorting of the items during placement of the dex file. This
|
||||||
|
* should *only* be set to true when this dex file was read in from an existing (valid) dex file,
|
||||||
|
* and no modifications were made (i.e. no items added or deleted). Otherwise it is likely that
|
||||||
|
* an invalid dex file will be generated.
|
||||||
|
*
|
||||||
|
* This is useful for the first use case (annotating an existing dex file). This ensures the items
|
||||||
|
* retain the same order as in the original dex file.
|
||||||
|
*/
|
||||||
|
private boolean inplace = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When true, this imposes an full ordering on all the items, to force them into a (possibly
|
||||||
|
* arbitrary) canonical order. When false, only the items that the dex format specifies
|
||||||
|
* an order for are sorted. The rest of the items are not ordered.
|
||||||
|
*
|
||||||
|
* This is useful for the second use case (canonicalizing an existing dex file) or possibly for
|
||||||
|
* the third use case (creating a dex file from scratch), if there is a need to write the new
|
||||||
|
* dex file in a canonical form.
|
||||||
|
*/
|
||||||
|
private boolean sortAllItems = false;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this is used to access the dex file from within inner classes, when they declare fields or
|
||||||
|
* variable that hide fields on this object
|
||||||
|
*/
|
||||||
private final DexFile dexFile = this;
|
private final DexFile dexFile = this;
|
||||||
|
|
||||||
private DexFile() {
|
|
||||||
|
/**
|
||||||
|
* A private constructor containing common code to initialize the section maps and lists
|
||||||
|
* @param preserveSignedRegisters If true, keep track of any registers in the debug information
|
||||||
|
* that are signed, so they will be written in the same format. See
|
||||||
|
* <code>getPreserveSignedRegisters()</code>
|
||||||
|
*/
|
||||||
|
private DexFile(boolean preserveSignedRegisters) {
|
||||||
|
this.preserveSignedRegisters = preserveSignedRegisters;
|
||||||
|
|
||||||
sectionsByType = new HashMap<ItemType, Section>(18);
|
sectionsByType = new HashMap<ItemType, Section>(18);
|
||||||
|
|
||||||
sectionsByType.put(ItemType.TYPE_ANNOTATION_ITEM, AnnotationsSection);
|
sectionsByType.put(ItemType.TYPE_ANNOTATION_ITEM, AnnotationsSection);
|
||||||
@ -94,25 +212,58 @@ public class DexFile
|
|||||||
AnnotationsSection,
|
AnnotationsSection,
|
||||||
EncodedArraysSection,
|
EncodedArraysSection,
|
||||||
ClassDataSection,
|
ClassDataSection,
|
||||||
DebugInfoItemsSection
|
DebugInfoItemsSection
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public DexFile(File file) {
|
|
||||||
this(file, false);
|
/**
|
||||||
|
* Construct a new DexFile instance by reading in the given dex file.
|
||||||
|
* @param file The dex file to read in
|
||||||
|
*/
|
||||||
|
public DexFile(String file) {
|
||||||
|
this(new File(file), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public DexFile(File file, boolean forDumping) {
|
/**
|
||||||
this();
|
* Construct a new DexFile instance by reading in the given dex file,
|
||||||
Input in = new ByteArrayInput(FileUtils.readFile(file));
|
* and optionally keep track of any registers in the debug information that are signed,
|
||||||
|
* so they will be written in the same format.
|
||||||
|
* @param file The dex file to read in
|
||||||
|
* @param preserveSignedRegisters If true, keep track of any registers in the debug information
|
||||||
|
* that are signed, so they will be written in the same format. See
|
||||||
|
* <code>getPreserveSignedRegisters()</code>
|
||||||
|
*/
|
||||||
|
public DexFile(String file, boolean preserveSignedRegisters) {
|
||||||
|
this(new File(file), preserveSignedRegisters);
|
||||||
|
}
|
||||||
|
|
||||||
this.forDumping = forDumping;
|
/**
|
||||||
|
* Construct a new DexFile instead by reading in the given dex file.
|
||||||
|
* @param file The dex file to read in
|
||||||
|
*/
|
||||||
|
public DexFile(File file) {
|
||||||
|
this(file, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct a new DexFile instance by reading in the given dex file,
|
||||||
|
* and optionally keep track of any registers in the debug information that are signed,
|
||||||
|
* so they will be written in the same format.
|
||||||
|
* @param file The dex file to read in
|
||||||
|
* @param preserveSignedRegisters If true, keep track of any registers in the debug information
|
||||||
|
* that are signed, so they will be written in the same format.
|
||||||
|
* @see #getPreserveSignedRegisters
|
||||||
|
*/
|
||||||
|
public DexFile(File file, boolean preserveSignedRegisters) {
|
||||||
|
this(preserveSignedRegisters);
|
||||||
|
|
||||||
|
Input in = new ByteArrayInput(FileUtils.readFile(file));
|
||||||
|
|
||||||
HeaderItemSection.readFrom(1, in);
|
HeaderItemSection.readFrom(1, in);
|
||||||
HeaderItem headerItem = HeaderItemSection.items.get(0);
|
HeaderItem headerItem = HeaderItemSection.items.get(0);
|
||||||
|
|
||||||
in.setCursor(headerItem.getMapOffset());
|
in.setCursor(headerItem.getMapOffset());
|
||||||
|
|
||||||
MapSection.readFrom(1, in);
|
MapSection.readFrom(1, in);
|
||||||
|
|
||||||
MapField[] mapEntries = MapSection.items.get(0).getMapEntries();
|
MapField[] mapEntries = MapSection.items.get(0).getMapEntries();
|
||||||
@ -121,6 +272,11 @@ public class DexFile
|
|||||||
mapMap.put(mapField.getSectionItemType().getMapValue(), mapField);
|
mapMap.put(mapField.getSectionItemType().getMapValue(), mapField);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This defines the order in which the sections are read in. This is not
|
||||||
|
* necessarily the order in which the appear in the file.
|
||||||
|
*/
|
||||||
|
//TODO: do we *need* to read them in a specific order, rather than the order that is in the file?
|
||||||
int[] sectionTypes = new int[] {
|
int[] sectionTypes = new int[] {
|
||||||
ItemType.TYPE_HEADER_ITEM.getMapValue(),
|
ItemType.TYPE_HEADER_ITEM.getMapValue(),
|
||||||
ItemType.TYPE_STRING_ID_ITEM.getMapValue(),
|
ItemType.TYPE_STRING_ID_ITEM.getMapValue(),
|
||||||
@ -147,64 +303,169 @@ public class DexFile
|
|||||||
if (mapField != null) {
|
if (mapField != null) {
|
||||||
Section section = sectionsByType.get(mapField.getSectionItemType());
|
Section section = sectionsByType.get(mapField.getSectionItemType());
|
||||||
if (section != null) {
|
if (section != null) {
|
||||||
in.setCursor(mapField.getSectionOffset());
|
in.setCursor(mapField.getCachedSectionOffset());
|
||||||
section.readFrom(mapField.getSectionSize(), in);
|
section.readFrom(mapField.getCachedSectionSize(), in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static DexFile makeBlankDexFile() {
|
/**
|
||||||
DexFile dexFile = new DexFile();
|
* Constructs a new, blank dex file. Classes can be added to this dex file by calling
|
||||||
try
|
* the <code>Section.intern()</code> method of <code>ClassDefsSection</code>
|
||||||
{
|
*/
|
||||||
dexFile.HeaderItemSection.intern(dexFile, new HeaderItem(dexFile, 0));
|
public DexFile() {
|
||||||
} catch (Exception ex) {
|
this(true);
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
dexFile.MapSection.intern(dexFile, MapItem.makeBlankMapItem(dexFile));
|
HeaderItemSection.intern(new HeaderItem(dexFile, 0));
|
||||||
return dexFile;
|
MapSection.intern(new MapItem(dexFile));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method to retrieve the header item
|
||||||
|
* @return the header item
|
||||||
|
*/
|
||||||
|
public HeaderItem getHeaderItem() {
|
||||||
|
return HeaderItemSection.getItems().get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience method to retrieve the map item
|
||||||
|
* @return the map item
|
||||||
|
*/
|
||||||
|
public MapItem getMapItem() {
|
||||||
|
return MapSection.getItems().get(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the <code>Section</code> containing items of the same type as the given item
|
||||||
|
* @param item Get the <code>Section</code> that contains items of this type
|
||||||
|
* @param <T> The specific item subclass - inferred from the passed item
|
||||||
|
* @return the <code>Section</code> containing items of the same type as the given item
|
||||||
|
*/
|
||||||
public <T extends Item> Section<T> getSectionForItem(T item) {
|
public <T extends Item> Section<T> getSectionForItem(T item) {
|
||||||
return sectionsByType.get(item.getItemType());
|
return sectionsByType.get(item.getItemType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the <code>Section</code> containing items of the given type
|
||||||
|
* @param itemType the type of item
|
||||||
|
* @return the <code>Section</code> containing items of the given type
|
||||||
|
*/
|
||||||
public Section getSectionForType(ItemType itemType) {
|
public Section getSectionForType(ItemType itemType) {
|
||||||
return sectionsByType.get(itemType);
|
return sectionsByType.get(itemType);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFileSize() {
|
/**
|
||||||
return fileSize;
|
* Get a boolean value indicating whether this dex file preserved any signed
|
||||||
|
* registers in the debug info as it read the dex file in. By default, the dex file
|
||||||
|
* doesn't check whether the registers are encoded as unsigned or signed values.
|
||||||
|
*
|
||||||
|
* This does *not* affect the actual register value that is read in. The value is
|
||||||
|
* read correctly regardless
|
||||||
|
*
|
||||||
|
* This does affect whether any signed registers will retain the same encoding or be
|
||||||
|
* forced to the (correct) unsigned encoding when the dex file is written back out.
|
||||||
|
*
|
||||||
|
* See the discussion about signed register values in the documentation for
|
||||||
|
* <code>DexFile</code>
|
||||||
|
* @return a boolean indicating whether this dex file preserved any signed registers
|
||||||
|
* as it was read in
|
||||||
|
*/
|
||||||
|
public boolean getPreserveSignedRegisters() {
|
||||||
|
return preserveSignedRegisters;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDataOffset() {
|
/**
|
||||||
return dataOffset;
|
* Get a boolean value indicating whether all items should be placed into a
|
||||||
|
* (possibly arbitrary) "canonical" ordering. If false, then only the items
|
||||||
|
* that must be ordered per the dex specification are sorted.
|
||||||
|
*
|
||||||
|
* When true, writing the dex file involves somewhat more overhead
|
||||||
|
*
|
||||||
|
* If both SortAllItems and Inplace are true, Inplace takes precedence
|
||||||
|
* @return a boolean value indicating whether all items should be sorted
|
||||||
|
*/
|
||||||
|
public boolean getSortAllItems() {
|
||||||
|
return this.sortAllItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDataSize() {
|
/**
|
||||||
return dataSize;
|
* Set a boolean value indicating whether all items should be placed into a
|
||||||
|
* (possibly arbitrary) "canonical" ordering. If false, then only the items
|
||||||
|
* that must be ordered per the dex specification are sorted.
|
||||||
|
*
|
||||||
|
* When true, writing the dex file involves somewhat more overhead
|
||||||
|
*
|
||||||
|
* If both SortAllItems and Inplace are true, Inplace takes precedence
|
||||||
|
* @param value a boolean value indicating whether all items should be sorted
|
||||||
|
*/
|
||||||
|
public void setSortAllItems(boolean value) {
|
||||||
|
this.sortAllItems = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isForDumping() {
|
/**
|
||||||
return forDumping;
|
* Get a boolean value indicating whether items in this dex file should be
|
||||||
|
* written back out "in-place", or whether the normal layout logic should be
|
||||||
|
* applied.
|
||||||
|
*
|
||||||
|
* This should only be used for a dex file that has been read from an existing
|
||||||
|
* dex file, and no modifications have been made to the dex file. Otherwise,
|
||||||
|
* there is a good chance that the resulting dex file will be invalid due to
|
||||||
|
* items that aren't placed correctly
|
||||||
|
*
|
||||||
|
* If both SortAllItems and Inplace are true, Inplace takes precedence
|
||||||
|
* @return a boolean value indicating whether items in this dex file should be
|
||||||
|
* written back out in-place.
|
||||||
|
*/
|
||||||
|
public boolean getInplace() {
|
||||||
|
return this.inplace;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void place(boolean sort) {
|
/**
|
||||||
int offset = 0;
|
* Set a boolean value indicating whether items in this dex file should be
|
||||||
|
* written back out "in-place", or whether the normal layout logic should be
|
||||||
|
* applied.
|
||||||
|
*
|
||||||
|
* This should only be used for a dex file that has been read from an existing
|
||||||
|
* dex file, and no modifications have been made to the dex file. Otherwise,
|
||||||
|
* there is a good chance that the resulting dex file will be invalid due to
|
||||||
|
* items that aren't placed correctly
|
||||||
|
*
|
||||||
|
* If both SortAllItems and Inplace are true, Inplace takes precedence
|
||||||
|
* @param value a boolean value indicating whether items in this dex file should be
|
||||||
|
* written back out in-place.
|
||||||
|
*/
|
||||||
|
public void setInplace(boolean value) {
|
||||||
|
this.inplace = value;
|
||||||
|
}
|
||||||
|
|
||||||
offset = HeaderItemSection.place(offset);
|
/**
|
||||||
|
* This method should be called before writing a dex file. It sorts the sections
|
||||||
|
* as needed or as indicated by <code>getSortAllItems()</code> and <code>getInplace()</code>,
|
||||||
|
* and then performs a pass through all of the items, finalizing the position (i.e.
|
||||||
|
* index and/or offset) of each item in the dex file.
|
||||||
|
*
|
||||||
|
* This step is needed primarily so that the indexes and offsets of all indexed and
|
||||||
|
* offsetted items are available when writing references to those items elsewhere.
|
||||||
|
*/
|
||||||
|
public void place() {
|
||||||
|
HeaderItem headerItem = getHeaderItem();
|
||||||
|
|
||||||
|
int offset = HeaderItemSection.place(0);
|
||||||
|
|
||||||
|
int dataOffset;
|
||||||
|
|
||||||
for (IndexedSection indexedSection: indexedSections) {
|
for (IndexedSection indexedSection: indexedSections) {
|
||||||
offset = indexedSection.place(offset);
|
offset = indexedSection.place(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
dataOffset = offset;
|
dataOffset = offset;
|
||||||
|
headerItem.setDataOffset(dataOffset);
|
||||||
|
|
||||||
|
//TODO: if inplace is true, we need to use the order of the sections as they were in the original file
|
||||||
for (OffsettedSection offsettedSection: offsettedSections) {
|
for (OffsettedSection offsettedSection: offsettedSections) {
|
||||||
if (sort) {
|
if (this.sortAllItems && !this.inplace) {
|
||||||
offsettedSection.sortSection();
|
offsettedSection.sortSection();
|
||||||
}
|
}
|
||||||
offset = offsettedSection.place(offset);
|
offset = offsettedSection.place(offset);
|
||||||
@ -212,12 +473,26 @@ public class DexFile
|
|||||||
|
|
||||||
offset = MapSection.place(offset);
|
offset = MapSection.place(offset);
|
||||||
|
|
||||||
dataSize = offset - dataOffset;
|
|
||||||
fileSize = offset;
|
headerItem.setFileSize(offset);
|
||||||
|
headerItem.setDataSize(offset - dataOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the dex file to the give <code>AnnotatedOutput</code> object. If
|
||||||
|
* <code>out.Annotates()</code> is true, then annotations that document the format
|
||||||
|
* of the dex file are written.
|
||||||
|
*
|
||||||
|
* You must call <code>place()</code> on this dex file, before calling this method
|
||||||
|
* @param out the AnnotatedOutput object to write the dex file and annotations to
|
||||||
|
*
|
||||||
|
* After calling this method, you should call <code>calcSignature()</code> and
|
||||||
|
* then <code>calcChecksum()</code> on the resulting byte array, to calculate the
|
||||||
|
* signature and checksum in the header
|
||||||
|
*/
|
||||||
public void writeTo(AnnotatedOutput out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
HeaderItemSection.writeTo(out);
|
HeaderItemSection.writeTo(out);
|
||||||
|
|
||||||
for (IndexedSection indexedSection: indexedSections) {
|
for (IndexedSection indexedSection: indexedSections) {
|
||||||
indexedSection.writeTo(out);
|
indexedSection.writeTo(out);
|
||||||
}
|
}
|
||||||
@ -229,48 +504,74 @@ public class DexFile
|
|||||||
MapSection.writeTo(out);
|
MapSection.writeTo(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
public final IndexedSection<HeaderItem> HeaderItemSection = new IndexedSection<HeaderItem>() {
|
/**
|
||||||
|
* The <code>IndexedSection</code> containing the sole <code>HeaderItem</code> item. Use
|
||||||
|
* <code>getHeaderItem()</code> instead.
|
||||||
|
*/
|
||||||
|
public final IndexedSection<HeaderItem> HeaderItemSection = new IndexedSection<HeaderItem>(this) {
|
||||||
protected HeaderItem make(int index) {
|
protected HeaderItem make(int index) {
|
||||||
return new HeaderItem(dexFile, index);
|
return new HeaderItem(dexFile, index);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public final IndexedSection<StringIdItem> StringIdsSection = new IndexedSection<StringIdItem>() {
|
/**
|
||||||
|
* The <code>IndexedSection</code> containing <code>StringIdItem</code> items
|
||||||
|
*/
|
||||||
|
public final IndexedSection<StringIdItem> StringIdsSection = new IndexedSection<StringIdItem>(this) {
|
||||||
protected StringIdItem make(int index) {
|
protected StringIdItem make(int index) {
|
||||||
return new StringIdItem(dexFile, index);
|
return new StringIdItem(dexFile, index);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public final IndexedSection<TypeIdItem> TypeIdsSection = new IndexedSection<TypeIdItem>() {
|
/**
|
||||||
|
* The <code>IndexedSection</code> containing <code>TypeIdItem</code> items
|
||||||
|
*/
|
||||||
|
public final IndexedSection<TypeIdItem> TypeIdsSection = new IndexedSection<TypeIdItem>(this) {
|
||||||
protected TypeIdItem make(int index) {
|
protected TypeIdItem make(int index) {
|
||||||
return new TypeIdItem(dexFile, index);
|
return new TypeIdItem(dexFile, index);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public final IndexedSection<ProtoIdItem> ProtoIdsSection = new IndexedSection<ProtoIdItem>() {
|
/**
|
||||||
|
* The <code>IndexedSection</code> containing <code>ProtoIdItem</code> items
|
||||||
|
*/
|
||||||
|
public final IndexedSection<ProtoIdItem> ProtoIdsSection = new IndexedSection<ProtoIdItem>(this) {
|
||||||
protected ProtoIdItem make(int index) {
|
protected ProtoIdItem make(int index) {
|
||||||
return new ProtoIdItem(dexFile, index);
|
return new ProtoIdItem(dexFile, index);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public final IndexedSection<FieldIdItem> FieldIdsSection = new IndexedSection<FieldIdItem>() {
|
/**
|
||||||
|
* The <code>IndexedSection</code> containing <code>FieldIdItem</code> items
|
||||||
|
*/
|
||||||
|
public final IndexedSection<FieldIdItem> FieldIdsSection = new IndexedSection<FieldIdItem>(this) {
|
||||||
protected FieldIdItem make(int index) {
|
protected FieldIdItem make(int index) {
|
||||||
return new FieldIdItem(dexFile, index);
|
return new FieldIdItem(dexFile, index);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public final IndexedSection<MethodIdItem> MethodIdsSection = new IndexedSection<MethodIdItem>() {
|
/**
|
||||||
|
* The <code>IndexedSection</code> containing <code>MethodIdItem</code> items
|
||||||
|
*/
|
||||||
|
public final IndexedSection<MethodIdItem> MethodIdsSection = new IndexedSection<MethodIdItem>(this) {
|
||||||
protected MethodIdItem make(int index) {
|
protected MethodIdItem make(int index) {
|
||||||
return new MethodIdItem(dexFile, index);
|
return new MethodIdItem(dexFile, index);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public final IndexedSection<ClassDefItem> ClassDefsSection = new IndexedSection<ClassDefItem>() {
|
/**
|
||||||
|
* The <code>IndexedSection</code> containing <code>ClassDefItem</code> items
|
||||||
|
*/
|
||||||
|
public final IndexedSection<ClassDefItem> ClassDefsSection = new IndexedSection<ClassDefItem>(this) {
|
||||||
protected ClassDefItem make(int index) {
|
protected ClassDefItem make(int index) {
|
||||||
return new ClassDefItem(dexFile, index);
|
return new ClassDefItem(dexFile, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int place(int offset) {
|
public int place(int offset) {
|
||||||
|
if (dexFile.getInplace()) {
|
||||||
|
return super.place(offset);
|
||||||
|
}
|
||||||
|
|
||||||
int ret = ClassDefItem.placeClassDefItems(this, offset);
|
int ret = ClassDefItem.placeClassDefItems(this, offset);
|
||||||
|
|
||||||
this.offset = items.get(0).getOffset();
|
this.offset = items.get(0).getOffset();
|
||||||
@ -278,7 +579,11 @@ public class DexFile
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public final IndexedSection<MapItem> MapSection = new IndexedSection<MapItem>() {
|
/**
|
||||||
|
* The <code>IndexedSection</code> containing the sole <code>MapItem</code>. Use
|
||||||
|
* <code>getMapItem()</code> instead
|
||||||
|
*/
|
||||||
|
public final IndexedSection<MapItem> MapSection = new IndexedSection<MapItem>(this) {
|
||||||
protected MapItem make(int index) {
|
protected MapItem make(int index) {
|
||||||
return new MapItem(dexFile, index);
|
return new MapItem(dexFile, index);
|
||||||
}
|
}
|
||||||
@ -289,64 +594,94 @@ public class DexFile
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public final OffsettedSection<TypeListItem> TypeListsSection = new OffsettedSection<TypeListItem>() {
|
/**
|
||||||
|
* The <code>OffsettedSection</code> containing <code>TypeListItem</code> items
|
||||||
|
*/
|
||||||
|
public final OffsettedSection<TypeListItem> TypeListsSection = new OffsettedSection<TypeListItem>(this) {
|
||||||
protected TypeListItem make(int offset) {
|
protected TypeListItem make(int offset) {
|
||||||
return new TypeListItem(dexFile, offset);
|
return new TypeListItem(dexFile, offset);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>OffsettedSection</code> containing <code>AnnotationSetRefList</code> items
|
||||||
|
*/
|
||||||
public final OffsettedSection<AnnotationSetRefList> AnnotationSetRefListsSection =
|
public final OffsettedSection<AnnotationSetRefList> AnnotationSetRefListsSection =
|
||||||
new OffsettedSection<AnnotationSetRefList>() {
|
new OffsettedSection<AnnotationSetRefList>(this) {
|
||||||
protected AnnotationSetRefList make(int offset) {
|
protected AnnotationSetRefList make(int offset) {
|
||||||
return new AnnotationSetRefList(dexFile, offset);
|
return new AnnotationSetRefList(dexFile, offset);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>OffsettedSection</code> containing <code>AnnotationSetItem</code> items
|
||||||
|
*/
|
||||||
public final OffsettedSection<AnnotationSetItem> AnnotationSetsSection =
|
public final OffsettedSection<AnnotationSetItem> AnnotationSetsSection =
|
||||||
new OffsettedSection<AnnotationSetItem>() {
|
new OffsettedSection<AnnotationSetItem>(this) {
|
||||||
protected AnnotationSetItem make(int offset) {
|
protected AnnotationSetItem make(int offset) {
|
||||||
return new AnnotationSetItem(dexFile, offset);
|
return new AnnotationSetItem(dexFile, offset);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public final OffsettedSection<ClassDataItem> ClassDataSection = new OffsettedSection<ClassDataItem>() {
|
/**
|
||||||
|
* The <code>OffsettedSection</code> containing <code>ClassDataItem</code> items
|
||||||
|
*/
|
||||||
|
public final OffsettedSection<ClassDataItem> ClassDataSection = new OffsettedSection<ClassDataItem>(this) {
|
||||||
protected ClassDataItem make(int offset) {
|
protected ClassDataItem make(int offset) {
|
||||||
return new ClassDataItem(dexFile, offset);
|
return new ClassDataItem(dexFile, offset);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public final OffsettedSection<CodeItem> CodeItemsSection = new OffsettedSection<CodeItem>() {
|
/**
|
||||||
|
* The <code>OffsettedSection</code> containing <code>CodeItem</code> items
|
||||||
|
*/
|
||||||
|
public final OffsettedSection<CodeItem> CodeItemsSection = new OffsettedSection<CodeItem>(this) {
|
||||||
protected CodeItem make(int offset) {
|
protected CodeItem make(int offset) {
|
||||||
return new CodeItem(dexFile, offset);
|
return new CodeItem(dexFile, offset);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public final OffsettedSection<StringDataItem> StringDataSection = new OffsettedSection<StringDataItem>() {
|
/**
|
||||||
|
* The <code>OffsettedSection</code> containing <code>StringDataItem</code> items
|
||||||
|
*/
|
||||||
|
public final OffsettedSection<StringDataItem> StringDataSection = new OffsettedSection<StringDataItem>(this) {
|
||||||
protected StringDataItem make(int offset) {
|
protected StringDataItem make(int offset) {
|
||||||
return new StringDataItem(offset);
|
return new StringDataItem(dexFile, offset);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public final OffsettedSection<DebugInfoItem> DebugInfoItemsSection = new OffsettedSection<DebugInfoItem>() {
|
/**
|
||||||
|
* The <code>OffsettedSection</code> containing <code>DebugInfoItem</code> items
|
||||||
|
*/
|
||||||
|
public final OffsettedSection<DebugInfoItem> DebugInfoItemsSection = new OffsettedSection<DebugInfoItem>(this) {
|
||||||
protected DebugInfoItem make(int offset) {
|
protected DebugInfoItem make(int offset) {
|
||||||
return new DebugInfoItem(dexFile, offset);
|
return new DebugInfoItem(dexFile, offset);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public final OffsettedSection<AnnotationItem> AnnotationsSection = new OffsettedSection<AnnotationItem>() {
|
/**
|
||||||
|
* The <code>OffsettedSection</code> containing <code>AnnotationItem</code> items
|
||||||
|
*/
|
||||||
|
public final OffsettedSection<AnnotationItem> AnnotationsSection = new OffsettedSection<AnnotationItem>(this) {
|
||||||
protected AnnotationItem make(int offset) {
|
protected AnnotationItem make(int offset) {
|
||||||
return new AnnotationItem(dexFile, offset);
|
return new AnnotationItem(dexFile, offset);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public final OffsettedSection<EncodedArrayItem> EncodedArraysSection = new OffsettedSection<EncodedArrayItem>() {
|
/**
|
||||||
|
* The <code>OffsettedSection</code> containing <code>EncodedArrayItem</code> items
|
||||||
|
*/
|
||||||
|
public final OffsettedSection<EncodedArrayItem> EncodedArraysSection = new OffsettedSection<EncodedArrayItem>(this) {
|
||||||
protected EncodedArrayItem make(int offset) {
|
protected EncodedArrayItem make(int offset) {
|
||||||
return new EncodedArrayItem(dexFile, offset);
|
return new EncodedArrayItem(dexFile, offset);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The <code>OffsettedSection</code> containing <code>AnnotationDirectoryItem</code> items
|
||||||
|
*/
|
||||||
public final OffsettedSection<AnnotationDirectoryItem> AnnotationDirectoriesSection =
|
public final OffsettedSection<AnnotationDirectoryItem> AnnotationDirectoriesSection =
|
||||||
new OffsettedSection<AnnotationDirectoryItem>() {
|
new OffsettedSection<AnnotationDirectoryItem>(this) {
|
||||||
protected AnnotationDirectoryItem make(int offset) {
|
protected AnnotationDirectoryItem make(int offset) {
|
||||||
return new AnnotationDirectoryItem(dexFile, offset);
|
return new AnnotationDirectoryItem(dexFile, offset);
|
||||||
}
|
}
|
||||||
@ -354,8 +689,9 @@ public class DexFile
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the signature for the <code>.dex</code> file in the
|
* Calculates the signature for the dex file in the given byte array,
|
||||||
* given array, and modify the array to contain it.
|
* and then writes the signature to the appropriate location in the header
|
||||||
|
* containing in the array
|
||||||
*
|
*
|
||||||
* @param bytes non-null; the bytes of the file
|
* @param bytes non-null; the bytes of the file
|
||||||
*/
|
*/
|
||||||
|
@ -37,7 +37,7 @@ public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> {
|
|||||||
private final ArrayEncodedValueSubField encodedArray;
|
private final ArrayEncodedValueSubField encodedArray;
|
||||||
|
|
||||||
public EncodedArrayItem(DexFile dexFile, int offset) {
|
public EncodedArrayItem(DexFile dexFile, int offset) {
|
||||||
super(offset);
|
super(dexFile, offset);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
encodedArray = new ArrayEncodedValueSubField(dexFile)
|
encodedArray = new ArrayEncodedValueSubField(dexFile)
|
||||||
@ -45,7 +45,7 @@ public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public EncodedArrayItem(DexFile dexFile, ArrayList<EncodedValue> encodedValues) {
|
public EncodedArrayItem(DexFile dexFile, ArrayList<EncodedValue> encodedValues) {
|
||||||
super(0);
|
super(dexFile, 0);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
encodedArray = new ArrayEncodedValueSubField(dexFile, encodedValues)
|
encodedArray = new ArrayEncodedValueSubField(dexFile, encodedValues)
|
||||||
|
@ -100,8 +100,7 @@ public class EncodedIndexedItemReference<T extends IndexedItem<T>>
|
|||||||
if (item == null) {
|
if (item == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
T copiedItem = copy.section.intern(dexFile, item);
|
copy.item = copy.section.intern(item);
|
||||||
copy.item = copiedItem;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public T getValue() {
|
public T getValue() {
|
||||||
|
@ -34,7 +34,7 @@ public class FieldIdItem extends IndexedItem<FieldIdItem> {
|
|||||||
private final IndexedItemReference<StringIdItem> fieldNameReferenceField;
|
private final IndexedItemReference<StringIdItem> fieldNameReferenceField;
|
||||||
|
|
||||||
public FieldIdItem(DexFile dexFile, int index) {
|
public FieldIdItem(DexFile dexFile, int index) {
|
||||||
super(index);
|
super(dexFile, index);
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
classTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
classTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||||
new ShortIntegerField(null), "class_idx"),
|
new ShortIntegerField(null), "class_idx"),
|
||||||
|
@ -63,8 +63,8 @@ public class HeaderItem extends IndexedItem<HeaderItem> {
|
|||||||
private final IntegerField dataSizeField;
|
private final IntegerField dataSizeField;
|
||||||
private final IntegerField dataOffField;
|
private final IntegerField dataOffField;
|
||||||
|
|
||||||
public HeaderItem(final DexFile file, int index) {
|
public HeaderItem(final DexFile dexFile, int index) {
|
||||||
super(index);
|
super(dexFile, index);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -84,64 +84,49 @@ public class HeaderItem extends IndexedItem<HeaderItem> {
|
|||||||
super.writeTo(out);
|
super.writeTo(out);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
fileSizeField = new IntegerField("file_size") {
|
fileSizeField = new IntegerField("file_size"),
|
||||||
public void writeTo(AnnotatedOutput out) {
|
|
||||||
cacheValue(file.getFileSize());
|
|
||||||
super.writeTo(out);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
headerSizeField = new IntegerField(HEADER_SIZE,"header_size"),
|
headerSizeField = new IntegerField(HEADER_SIZE,"header_size"),
|
||||||
endianTagField = new IntegerField(ENDIAN_TAG,"endian_tag"),
|
endianTagField = new IntegerField(ENDIAN_TAG,"endian_tag"),
|
||||||
linkSizeField = new IntegerField(0,"link_size"),
|
linkSizeField = new IntegerField(0,"link_size"),
|
||||||
linkOffField = new IntegerField(0,"link_off"),
|
linkOffField = new IntegerField(0,"link_off"),
|
||||||
mapOffField = new IntegerField("map_off") {
|
mapOffField = new IntegerField("map_off") {
|
||||||
public void writeTo(AnnotatedOutput out) {
|
public void writeTo(AnnotatedOutput out) {
|
||||||
cacheValue(file.MapSection.getOffset());
|
cacheValue(dexFile.MapSection.getOffset());
|
||||||
super.writeTo(out);
|
super.writeTo(out);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
StringIdsHeaderField = new SectionHeaderInfo("string_ids") {
|
StringIdsHeaderField = new SectionHeaderInfo("string_ids") {
|
||||||
protected Section getSection() {
|
protected Section getSection() {
|
||||||
return file.StringIdsSection;
|
return dexFile.StringIdsSection;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
TypeIdsHeaderField = new SectionHeaderInfo("type_ids") {
|
TypeIdsHeaderField = new SectionHeaderInfo("type_ids") {
|
||||||
protected Section getSection() {
|
protected Section getSection() {
|
||||||
return file.TypeIdsSection;
|
return dexFile.TypeIdsSection;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ProtoIdsHeaderField = new SectionHeaderInfo("proto_ids") {
|
ProtoIdsHeaderField = new SectionHeaderInfo("proto_ids") {
|
||||||
protected Section getSection() {
|
protected Section getSection() {
|
||||||
return file.ProtoIdsSection;
|
return dexFile.ProtoIdsSection;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
FieldIdsHeaderField = new SectionHeaderInfo("field_ids") {
|
FieldIdsHeaderField = new SectionHeaderInfo("field_ids") {
|
||||||
protected Section getSection() {
|
protected Section getSection() {
|
||||||
return file.FieldIdsSection;
|
return dexFile.FieldIdsSection;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
MethodIdsHeaderField = new SectionHeaderInfo("method_ids") {
|
MethodIdsHeaderField = new SectionHeaderInfo("method_ids") {
|
||||||
protected Section getSection() {
|
protected Section getSection() {
|
||||||
return file.MethodIdsSection;
|
return dexFile.MethodIdsSection;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ClassDefsHeaderField = new SectionHeaderInfo("class_defs") {
|
ClassDefsHeaderField = new SectionHeaderInfo("class_defs") {
|
||||||
protected Section getSection() {
|
protected Section getSection() {
|
||||||
return file.ClassDefsSection;
|
return dexFile.ClassDefsSection;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
dataSizeField = new IntegerField("data_size") {
|
dataSizeField = new IntegerField("data_size"),
|
||||||
public void writeTo(AnnotatedOutput out) {
|
dataOffField = new IntegerField("data_off")
|
||||||
cacheValue(file.getDataSize());
|
|
||||||
super.writeTo(out);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dataOffField = new IntegerField("data_off") {
|
|
||||||
public void writeTo(AnnotatedOutput out) {
|
|
||||||
cacheValue(file.getDataOffset());
|
|
||||||
super.writeTo(out);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
} catch (UnsupportedEncodingException ex) {
|
} catch (UnsupportedEncodingException ex) {
|
||||||
throw new RuntimeException("Error while creating the magic header field.", ex);
|
throw new RuntimeException("Error while creating the magic header field.", ex);
|
||||||
@ -168,4 +153,16 @@ public class HeaderItem extends IndexedItem<HeaderItem> {
|
|||||||
//there is only 1 header item
|
//there is only 1 header item
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void setFileSize(int size) {
|
||||||
|
this.fileSizeField.cacheValue(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setDataSize(int size) {
|
||||||
|
this.dataSizeField.cacheValue(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setDataOffset(int offset) {
|
||||||
|
this.dataOffField.cacheValue(offset);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,8 @@
|
|||||||
package org.jf.dexlib;
|
package org.jf.dexlib;
|
||||||
|
|
||||||
public abstract class IndexedItem<T extends IndexedItem> extends Item<T> {
|
public abstract class IndexedItem<T extends IndexedItem> extends Item<T> {
|
||||||
protected IndexedItem(int index) {
|
protected IndexedItem(DexFile dexFile, int index) {
|
||||||
|
super(dexFile);
|
||||||
this.index = index;
|
this.index = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -33,7 +33,8 @@ import org.jf.dexlib.Util.Input;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
public abstract class IndexedSection<T extends IndexedItem<T>> extends Section<T> {
|
public abstract class IndexedSection<T extends IndexedItem<T>> extends Section<T> {
|
||||||
public IndexedSection() {
|
public IndexedSection(DexFile dexFile) {
|
||||||
|
super(dexFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public T getByIndex(int index) {
|
public T getByIndex(int index) {
|
||||||
@ -61,7 +62,7 @@ public abstract class IndexedSection<T extends IndexedItem<T>> extends Section<T
|
|||||||
|
|
||||||
protected abstract T make(int index);
|
protected abstract T make(int index);
|
||||||
|
|
||||||
public T intern(DexFile dexFile, T item) {
|
public T intern(T item) {
|
||||||
T itemToReturn = getInternedItem(item);
|
T itemToReturn = getInternedItem(item);
|
||||||
|
|
||||||
if (itemToReturn == null) {
|
if (itemToReturn == null) {
|
||||||
@ -78,7 +79,9 @@ public abstract class IndexedSection<T extends IndexedItem<T>> extends Section<T
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int place(int offset) {
|
public int place(int offset) {
|
||||||
sortSection();
|
if (!dexFile.getInplace()) {
|
||||||
|
sortSection();
|
||||||
|
}
|
||||||
|
|
||||||
return super.place(offset);
|
return super.place(offset);
|
||||||
}
|
}
|
||||||
|
@ -34,10 +34,12 @@ import org.jf.dexlib.Util.Input;
|
|||||||
public abstract class Item<T extends Item> implements Comparable<T> {
|
public abstract class Item<T extends Item> implements Comparable<T> {
|
||||||
protected int offset = -1;
|
protected int offset = -1;
|
||||||
protected int index = -1;
|
protected int index = -1;
|
||||||
|
protected final DexFile dexFile;
|
||||||
|
|
||||||
protected Field[] fields;
|
protected Field[] fields;
|
||||||
|
|
||||||
protected Item() {
|
protected Item(DexFile dexFile) {
|
||||||
|
this.dexFile = dexFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPlaced() {
|
public boolean isPlaced() {
|
||||||
|
@ -70,7 +70,7 @@ public abstract class ItemReference<T extends Item<T>, S extends ItemReference<T
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Section<T> section = copy.getSection();
|
Section<T> section = copy.getSection();
|
||||||
T copiedItem = section.intern(dexFile, referencedItem);
|
T copiedItem = section.intern(referencedItem);
|
||||||
copy.setReference(copiedItem);
|
copy.setReference(copiedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,15 +30,14 @@ package org.jf.dexlib;
|
|||||||
|
|
||||||
public class MapField extends CompositeField<MapField> {
|
public class MapField extends CompositeField<MapField> {
|
||||||
private final ShortIntegerField sectionTypeField;
|
private final ShortIntegerField sectionTypeField;
|
||||||
private final ShortIntegerField unusedField;
|
|
||||||
private final SectionHeaderInfo sectionInfoField;
|
private final SectionHeaderInfo sectionInfoField;
|
||||||
|
|
||||||
public MapField(final DexFile dexFile) {
|
protected MapField(final DexFile dexFile) {
|
||||||
super("map_entry");
|
super("map_entry");
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
//TODO: add an annotation for the item type
|
//TODO: add an annotation for the item type
|
||||||
sectionTypeField = new ShortIntegerField("type"),
|
sectionTypeField = new ShortIntegerField("type"),
|
||||||
unusedField = new ShortIntegerField((short)0, "not used"),
|
new ShortIntegerField((short)0, "padding"),
|
||||||
sectionInfoField = new SectionHeaderInfo("section") {
|
sectionInfoField = new SectionHeaderInfo("section") {
|
||||||
protected Section getSection() {
|
protected Section getSection() {
|
||||||
return dexFile.getSectionForType(getSectionItemType());
|
return dexFile.getSectionForType(getSectionItemType());
|
||||||
@ -47,24 +46,46 @@ public class MapField extends CompositeField<MapField> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapField(final DexFile dexFile, short sectionType) {
|
protected MapField(final DexFile dexFile, short sectionType) {
|
||||||
this(dexFile);
|
this(dexFile);
|
||||||
sectionTypeField.cacheValue(sectionType);
|
sectionTypeField.cacheValue(sectionType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the <code>ItemType</code> of the section that this map field represents
|
||||||
|
* @return The <code>ItemType</code> of the section that this map field represents
|
||||||
|
*/
|
||||||
public ItemType getSectionItemType() {
|
public ItemType getSectionItemType() {
|
||||||
return ItemType.fromInt(sectionTypeField.getCachedValue());
|
return ItemType.fromInt(sectionTypeField.getCachedValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the <code>Section</code> object that this map field represents
|
||||||
|
* @return The <code>Section</code> object that this map field represents
|
||||||
|
*/
|
||||||
public Section getSection() {
|
public Section getSection() {
|
||||||
|
Section s;
|
||||||
return sectionInfoField.getSection();
|
return sectionInfoField.getSection();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSectionSize() {
|
/**
|
||||||
|
* This returns the cached size of the section that this map field represents. This is used while
|
||||||
|
* reading in the given section, to retrieve the size of the section that is stored in this map
|
||||||
|
* field.
|
||||||
|
*
|
||||||
|
* @return the cached size of the section that this map field represents
|
||||||
|
*/
|
||||||
|
protected int getCachedSectionSize() {
|
||||||
return sectionInfoField.getSectionSize();
|
return sectionInfoField.getSectionSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSectionOffset() {
|
/**
|
||||||
|
* This returns the cached size of the section that this map field represents. This is used while
|
||||||
|
* reading in the given section, to retrieve the offset of the section that is stored in this map
|
||||||
|
* field
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
protected int getCachedSectionOffset() {
|
||||||
return sectionInfoField.getSectionOffset();
|
return sectionInfoField.getSectionOffset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,8 +35,8 @@ import java.util.Comparator;
|
|||||||
public class MapItem extends IndexedItem<MapItem> {
|
public class MapItem extends IndexedItem<MapItem> {
|
||||||
private ArrayList<MapField> mapEntries = new ArrayList<MapField>();
|
private ArrayList<MapField> mapEntries = new ArrayList<MapField>();
|
||||||
|
|
||||||
public MapItem(final DexFile dexFile, int index) {
|
protected MapItem(final DexFile dexFile, int index) {
|
||||||
super(index);
|
super(dexFile, index);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
new ListSizeField(mapEntries, new IntegerField("size")),
|
new ListSizeField(mapEntries, new IntegerField("size")),
|
||||||
@ -48,6 +48,29 @@ public class MapItem extends IndexedItem<MapItem> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected MapItem(final DexFile dexFile) {
|
||||||
|
this(dexFile, 0);
|
||||||
|
|
||||||
|
mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_HEADER_ITEM.getMapValue()));
|
||||||
|
mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_STRING_ID_ITEM.getMapValue()));
|
||||||
|
mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_TYPE_ID_ITEM.getMapValue()));
|
||||||
|
mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_PROTO_ID_ITEM.getMapValue()));
|
||||||
|
mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_FIELD_ID_ITEM.getMapValue()));
|
||||||
|
mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_METHOD_ID_ITEM.getMapValue()));
|
||||||
|
mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_CLASS_DEF_ITEM.getMapValue()));
|
||||||
|
mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_STRING_DATA_ITEM.getMapValue()));
|
||||||
|
mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_ENCODED_ARRAY_ITEM.getMapValue()));
|
||||||
|
mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_ANNOTATION_ITEM.getMapValue()));
|
||||||
|
mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_ANNOTATION_SET_ITEM.getMapValue()));
|
||||||
|
mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_ANNOTATION_SET_REF_LIST.getMapValue()));
|
||||||
|
mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM.getMapValue()));
|
||||||
|
mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_TYPE_LIST.getMapValue()));
|
||||||
|
mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_DEBUG_INFO_ITEM.getMapValue()));
|
||||||
|
mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_CODE_ITEM.getMapValue()));
|
||||||
|
mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_CLASS_DATA_ITEM.getMapValue()));
|
||||||
|
mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_MAP_LIST.getMapValue()));
|
||||||
|
}
|
||||||
|
|
||||||
public int place(int index, int offset) {
|
public int place(int index, int offset) {
|
||||||
|
|
||||||
//we have to check if there are any empty sections before we place this item,
|
//we have to check if there are any empty sections before we place this item,
|
||||||
@ -72,32 +95,6 @@ public class MapItem extends IndexedItem<MapItem> {
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MapItem makeBlankMapItem(DexFile dexFile) {
|
|
||||||
MapItem mapItem = new MapItem(dexFile, 0);
|
|
||||||
|
|
||||||
mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_HEADER_ITEM.getMapValue()));
|
|
||||||
mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_STRING_ID_ITEM.getMapValue()));
|
|
||||||
mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_TYPE_ID_ITEM.getMapValue()));
|
|
||||||
mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_PROTO_ID_ITEM.getMapValue()));
|
|
||||||
mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_FIELD_ID_ITEM.getMapValue()));
|
|
||||||
mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_METHOD_ID_ITEM.getMapValue()));
|
|
||||||
mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_CLASS_DEF_ITEM.getMapValue()));
|
|
||||||
mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_STRING_DATA_ITEM.getMapValue()));
|
|
||||||
mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_ENCODED_ARRAY_ITEM.getMapValue()));
|
|
||||||
mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_ANNOTATION_ITEM.getMapValue()));
|
|
||||||
mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_ANNOTATION_SET_ITEM.getMapValue()));
|
|
||||||
mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_ANNOTATION_SET_REF_LIST.getMapValue()));
|
|
||||||
mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_ANNOTATIONS_DIRECTORY_ITEM.getMapValue()));
|
|
||||||
mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_TYPE_LIST.getMapValue()));
|
|
||||||
mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_DEBUG_INFO_ITEM.getMapValue()));
|
|
||||||
mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_CODE_ITEM.getMapValue()));
|
|
||||||
mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_CLASS_DATA_ITEM.getMapValue()));
|
|
||||||
mapItem.mapEntries.add(new MapField(dexFile, (short)ItemType.TYPE_MAP_LIST.getMapValue()));
|
|
||||||
|
|
||||||
|
|
||||||
return mapItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MapField[] getMapEntries() {
|
public MapField[] getMapEntries() {
|
||||||
return mapEntries.toArray(new MapField[1]);
|
return mapEntries.toArray(new MapField[1]);
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,7 @@ public class MethodIdItem extends IndexedItem<MethodIdItem> {
|
|||||||
private final IndexedItemReference<StringIdItem> methodNameReferenceField;
|
private final IndexedItemReference<StringIdItem> methodNameReferenceField;
|
||||||
|
|
||||||
public MethodIdItem(DexFile dexFile, int index) {
|
public MethodIdItem(DexFile dexFile, int index) {
|
||||||
super(index);
|
super(dexFile, index);
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
classTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
classTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||||
new ShortIntegerField(null), "class_idx"),
|
new ShortIntegerField(null), "class_idx"),
|
||||||
|
@ -29,7 +29,8 @@
|
|||||||
package org.jf.dexlib;
|
package org.jf.dexlib;
|
||||||
|
|
||||||
public abstract class OffsettedItem<T extends OffsettedItem<T>> extends Item<T> {
|
public abstract class OffsettedItem<T extends OffsettedItem<T>> extends Item<T> {
|
||||||
public OffsettedItem(int offset) {
|
public OffsettedItem(DexFile dexFile, int offset) {
|
||||||
|
super(dexFile);
|
||||||
this.offset = offset;
|
this.offset = offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,8 @@ import java.util.Comparator;
|
|||||||
public abstract class OffsettedSection<T extends OffsettedItem<T>> extends Section<T> {
|
public abstract class OffsettedSection<T extends OffsettedItem<T>> extends Section<T> {
|
||||||
protected HashMap<Integer, T> itemsByOffset;
|
protected HashMap<Integer, T> itemsByOffset;
|
||||||
|
|
||||||
public OffsettedSection() {
|
public OffsettedSection(DexFile dexFile) {
|
||||||
|
super(dexFile);
|
||||||
itemsByOffset = new HashMap<Integer, T>();
|
itemsByOffset = new HashMap<Integer, T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -77,7 +78,7 @@ public abstract class OffsettedSection<T extends OffsettedItem<T>> extends Secti
|
|||||||
|
|
||||||
protected abstract T make(int offset);
|
protected abstract T make(int offset);
|
||||||
|
|
||||||
public T intern(DexFile dexFile, T item) {
|
public T intern(T item) {
|
||||||
T itemToReturn = getInternedItem(item);
|
T itemToReturn = getInternedItem(item);
|
||||||
|
|
||||||
if (itemToReturn == null) {
|
if (itemToReturn == null) {
|
||||||
|
@ -36,7 +36,7 @@ public class ProtoIdItem extends IndexedItem<ProtoIdItem> {
|
|||||||
private final OffsettedItemReference<TypeListItem> parametersReferenceField;
|
private final OffsettedItemReference<TypeListItem> parametersReferenceField;
|
||||||
|
|
||||||
public ProtoIdItem(DexFile dexFile, int index) {
|
public ProtoIdItem(DexFile dexFile, int index) {
|
||||||
super(index);
|
super(dexFile, index);
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
shortyDescriptorReferenceField = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
shortyDescriptorReferenceField = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||||
new IntegerField(null), "shorty_idx"),
|
new IntegerField(null), "shorty_idx"),
|
||||||
@ -88,7 +88,7 @@ public class ProtoIdItem extends IndexedItem<ProtoIdItem> {
|
|||||||
if (typeList == null) {
|
if (typeList == null) {
|
||||||
return 0;
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
return typeList.getCount();
|
return typeList.getTypeCount();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -37,8 +37,9 @@ import java.util.List;
|
|||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
public abstract class Section<T extends Item> {
|
public abstract class Section<T extends Item> {
|
||||||
protected ArrayList<T> items;
|
protected final ArrayList<T> items;
|
||||||
protected HashMap<T, T> uniqueItems = null;
|
protected HashMap<T, T> uniqueItems = null;
|
||||||
|
protected final DexFile dexFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When offset > -1, this section is "placed" at the specified offset. All
|
* When offset > -1, this section is "placed" at the specified offset. All
|
||||||
@ -49,7 +50,8 @@ public abstract class Section<T extends Item> {
|
|||||||
*/
|
*/
|
||||||
protected int offset = -1;
|
protected int offset = -1;
|
||||||
|
|
||||||
public Section() {
|
public Section(DexFile dexFile) {
|
||||||
|
this.dexFile = dexFile;
|
||||||
items = new ArrayList<T>();
|
items = new ArrayList<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,5 +138,5 @@ public abstract class Section<T extends Item> {
|
|||||||
Collections.sort(items);
|
Collections.sort(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract T intern(DexFile dexFile, T item);
|
public abstract T intern(T item);
|
||||||
}
|
}
|
||||||
|
@ -37,8 +37,8 @@ public class StringDataItem extends OffsettedItem<StringDataItem> implements Com
|
|||||||
private final Leb128Field stringSize;
|
private final Leb128Field stringSize;
|
||||||
private final NullTerminatedByteArrayField stringByteArray;
|
private final NullTerminatedByteArrayField stringByteArray;
|
||||||
|
|
||||||
public StringDataItem(int offset) {
|
public StringDataItem(DexFile dexFile, int offset) {
|
||||||
super(offset);
|
super(dexFile, offset);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
stringSize = new Leb128Field("string_length"),
|
stringSize = new Leb128Field("string_length"),
|
||||||
@ -46,8 +46,8 @@ public class StringDataItem extends OffsettedItem<StringDataItem> implements Com
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public StringDataItem(String value) {
|
public StringDataItem(DexFile dexFile, String value) {
|
||||||
super(-1);
|
super(dexFile, -1);
|
||||||
|
|
||||||
this.value = value;
|
this.value = value;
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ public class StringIdItem extends IndexedItem<StringIdItem> {
|
|||||||
private final OffsettedItemReference<StringDataItem> stringDataReferenceField;
|
private final OffsettedItemReference<StringDataItem> stringDataReferenceField;
|
||||||
|
|
||||||
public StringIdItem(DexFile dexFile, int index) {
|
public StringIdItem(DexFile dexFile, int index) {
|
||||||
super(index);
|
super(dexFile, index);
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
stringDataReferenceField = new OffsettedItemReference<StringDataItem>(dexFile.StringDataSection,
|
stringDataReferenceField = new OffsettedItemReference<StringDataItem>(dexFile.StringDataSection,
|
||||||
new IntegerField(null), "string_data_off")
|
new IntegerField(null), "string_data_off")
|
||||||
@ -47,7 +47,7 @@ public class StringIdItem extends IndexedItem<StringIdItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public StringIdItem(DexFile dexFile, String value) {
|
public StringIdItem(DexFile dexFile, String value) {
|
||||||
this(dexFile, new StringDataItem(value));
|
this(dexFile, new StringDataItem(dexFile, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int getAlignment() {
|
protected int getAlignment() {
|
||||||
|
@ -32,7 +32,7 @@ public class TypeIdItem extends IndexedItem<TypeIdItem> {
|
|||||||
private final IndexedItemReference<StringIdItem> typeDescriptorReferenceField;
|
private final IndexedItemReference<StringIdItem> typeDescriptorReferenceField;
|
||||||
|
|
||||||
public TypeIdItem(DexFile dexFile, int index) {
|
public TypeIdItem(DexFile dexFile, int index) {
|
||||||
super(index);
|
super(dexFile, index);
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
typeDescriptorReferenceField = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
typeDescriptorReferenceField = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||||
new IntegerField(null), "descriptor_idx")
|
new IntegerField(null), "descriptor_idx")
|
||||||
|
@ -34,14 +34,13 @@ import java.util.List;
|
|||||||
public class TypeListItem extends OffsettedItem<TypeListItem> {
|
public class TypeListItem extends OffsettedItem<TypeListItem> {
|
||||||
private final ArrayList<IndexedItemReference<TypeIdItem>> typeList = new ArrayList<IndexedItemReference<TypeIdItem>>();
|
private final ArrayList<IndexedItemReference<TypeIdItem>> typeList = new ArrayList<IndexedItemReference<TypeIdItem>>();
|
||||||
|
|
||||||
private final ListSizeField sizeField;
|
|
||||||
private final FieldListField<IndexedItemReference<TypeIdItem>> listField;
|
private final FieldListField<IndexedItemReference<TypeIdItem>> listField;
|
||||||
|
|
||||||
public TypeListItem(final DexFile dexFile, int offset) {
|
public TypeListItem(final DexFile dexFile, int offset) {
|
||||||
super(offset);
|
super(dexFile, offset);
|
||||||
|
|
||||||
fields = new Field[] {
|
fields = new Field[] {
|
||||||
sizeField = new ListSizeField(typeList, new IntegerField("size")),
|
new ListSizeField(typeList, new IntegerField("size")),
|
||||||
listField = new FieldListField<IndexedItemReference<TypeIdItem>>(typeList, "type_item") {
|
listField = new FieldListField<IndexedItemReference<TypeIdItem>>(typeList, "type_item") {
|
||||||
protected IndexedItemReference<TypeIdItem> make() {
|
protected IndexedItemReference<TypeIdItem> make() {
|
||||||
return new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
return new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||||
@ -61,6 +60,7 @@ public class TypeListItem extends OffsettedItem<TypeListItem> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: write a read only List<T> wrapper for List<ItemReference<T>> and return that instead
|
||||||
public List<TypeIdItem> getTypes() {
|
public List<TypeIdItem> getTypes() {
|
||||||
ArrayList<TypeIdItem> list = new ArrayList<TypeIdItem>(typeList.size());
|
ArrayList<TypeIdItem> list = new ArrayList<TypeIdItem>(typeList.size());
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ public class TypeListItem extends OffsettedItem<TypeListItem> {
|
|||||||
return wordCount;
|
return wordCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCount() {
|
public int getTypeCount() {
|
||||||
return typeList.size();
|
return typeList.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ public class TryListBuilderTest
|
|||||||
public void singleTryTest() {
|
public void singleTryTest() {
|
||||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||||
|
|
||||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
DexFile dexFile = new DexFile();
|
||||||
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
|
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
|
||||||
tryListBuilder.addHandler(typeIdItem, 2, 5, 100);
|
tryListBuilder.addHandler(typeIdItem, 2, 5, 100);
|
||||||
|
|
||||||
@ -98,7 +98,7 @@ public class TryListBuilderTest
|
|||||||
public void singleTryWithCatchAllTest() {
|
public void singleTryWithCatchAllTest() {
|
||||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||||
|
|
||||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
DexFile dexFile = new DexFile();
|
||||||
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
|
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
|
||||||
tryListBuilder.addHandler(typeIdItem, 2, 5, 100);
|
tryListBuilder.addHandler(typeIdItem, 2, 5, 100);
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ public class TryListBuilderTest
|
|||||||
// |-----|
|
// |-----|
|
||||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||||
|
|
||||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
DexFile dexFile = new DexFile();
|
||||||
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
|
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
|
||||||
tryListBuilder.addHandler(typeIdItem, 2, 5, 100);
|
tryListBuilder.addHandler(typeIdItem, 2, 5, 100);
|
||||||
|
|
||||||
@ -138,7 +138,7 @@ public class TryListBuilderTest
|
|||||||
// |-----|
|
// |-----|
|
||||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||||
|
|
||||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
DexFile dexFile = new DexFile();
|
||||||
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
|
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
|
||||||
tryListBuilder.addHandler(typeIdItem, 2, 5, 100);
|
tryListBuilder.addHandler(typeIdItem, 2, 5, 100);
|
||||||
|
|
||||||
@ -159,7 +159,7 @@ public class TryListBuilderTest
|
|||||||
//|-----|
|
//|-----|
|
||||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||||
|
|
||||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
DexFile dexFile = new DexFile();
|
||||||
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
|
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
|
||||||
tryListBuilder.addHandler(typeIdItem, 5, 10, 101);
|
tryListBuilder.addHandler(typeIdItem, 5, 10, 101);
|
||||||
tryListBuilder.addHandler(typeIdItem, 2, 5, 100);
|
tryListBuilder.addHandler(typeIdItem, 2, 5, 100);
|
||||||
@ -179,7 +179,7 @@ public class TryListBuilderTest
|
|||||||
//|-----|
|
//|-----|
|
||||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||||
|
|
||||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
DexFile dexFile = new DexFile();
|
||||||
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
|
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
|
||||||
|
|
||||||
tryListBuilder.addHandler(typeIdItem, 10, 15, 101);
|
tryListBuilder.addHandler(typeIdItem, 10, 15, 101);
|
||||||
@ -201,7 +201,7 @@ public class TryListBuilderTest
|
|||||||
//|-----|
|
//|-----|
|
||||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||||
|
|
||||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
DexFile dexFile = new DexFile();
|
||||||
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
||||||
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
||||||
|
|
||||||
@ -221,7 +221,7 @@ public class TryListBuilderTest
|
|||||||
// |-----|
|
// |-----|
|
||||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||||
|
|
||||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
DexFile dexFile = new DexFile();
|
||||||
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
||||||
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
||||||
|
|
||||||
@ -245,7 +245,7 @@ public class TryListBuilderTest
|
|||||||
//|-----|
|
//|-----|
|
||||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||||
|
|
||||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
DexFile dexFile = new DexFile();
|
||||||
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
||||||
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
||||||
|
|
||||||
@ -268,7 +268,7 @@ public class TryListBuilderTest
|
|||||||
// |---|
|
// |---|
|
||||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||||
|
|
||||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
DexFile dexFile = new DexFile();
|
||||||
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
||||||
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
||||||
|
|
||||||
@ -291,7 +291,7 @@ public class TryListBuilderTest
|
|||||||
//|-----|
|
//|-----|
|
||||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||||
|
|
||||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
DexFile dexFile = new DexFile();
|
||||||
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
||||||
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
||||||
|
|
||||||
@ -314,7 +314,7 @@ public class TryListBuilderTest
|
|||||||
//|---|
|
//|---|
|
||||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||||
|
|
||||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
DexFile dexFile = new DexFile();
|
||||||
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
||||||
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
||||||
|
|
||||||
@ -336,7 +336,7 @@ public class TryListBuilderTest
|
|||||||
//|-----|
|
//|-----|
|
||||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||||
|
|
||||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
DexFile dexFile = new DexFile();
|
||||||
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
||||||
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
||||||
|
|
||||||
@ -358,7 +358,7 @@ public class TryListBuilderTest
|
|||||||
// |---|
|
// |---|
|
||||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||||
|
|
||||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
DexFile dexFile = new DexFile();
|
||||||
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
||||||
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
||||||
|
|
||||||
@ -380,7 +380,7 @@ public class TryListBuilderTest
|
|||||||
//|-----|
|
//|-----|
|
||||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||||
|
|
||||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
DexFile dexFile = new DexFile();
|
||||||
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
||||||
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
||||||
|
|
||||||
@ -404,7 +404,7 @@ public class TryListBuilderTest
|
|||||||
//|--------------------|
|
//|--------------------|
|
||||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||||
|
|
||||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
DexFile dexFile = new DexFile();
|
||||||
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
||||||
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
||||||
TypeIdItem typeIdItem3= new TypeIdItem(dexFile, "Ljava/lang/Exception3;");
|
TypeIdItem typeIdItem3= new TypeIdItem(dexFile, "Ljava/lang/Exception3;");
|
||||||
@ -434,7 +434,7 @@ public class TryListBuilderTest
|
|||||||
// |---|
|
// |---|
|
||||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||||
|
|
||||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
DexFile dexFile = new DexFile();
|
||||||
|
|
||||||
tryListBuilder.addCatchAllHandler(2, 8, 100);
|
tryListBuilder.addCatchAllHandler(2, 8, 100);
|
||||||
tryListBuilder.addCatchAllHandler(4, 6, 101);
|
tryListBuilder.addCatchAllHandler(4, 6, 101);
|
||||||
@ -454,7 +454,7 @@ public class TryListBuilderTest
|
|||||||
//|-----|
|
//|-----|
|
||||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||||
|
|
||||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
DexFile dexFile = new DexFile();
|
||||||
|
|
||||||
tryListBuilder.addCatchAllHandler(4, 6, 100);
|
tryListBuilder.addCatchAllHandler(4, 6, 100);
|
||||||
tryListBuilder.addCatchAllHandler(2, 8, 101);
|
tryListBuilder.addCatchAllHandler(2, 8, 101);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user