- 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:
JesusFreke@JesusFreke.com 2009-06-23 01:44:36 +00:00
parent d166b746b9
commit 281b510a9c
35 changed files with 565 additions and 192 deletions

View File

@ -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>

View File

@ -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>(

View File

@ -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"),

View File

@ -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")),

View File

@ -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")),

View File

@ -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,

View File

@ -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;

View File

@ -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;

View File

@ -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>();

View File

@ -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:

View File

@ -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() {

View File

@ -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"),

View File

@ -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"),

View File

@ -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"),

View File

@ -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
*/ */

View 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)

View File

@ -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() {

View File

@ -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"),

View File

@ -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);
}
} }

View File

@ -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;
} }
} }

View File

@ -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);
} }

View File

@ -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() {

View File

@ -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);
} }

View File

@ -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();
} }
} }

View File

@ -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]);
} }

View File

@ -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"),

View File

@ -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;
} }
} }

View File

@ -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) {

View File

@ -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();
} }
} }

View File

@ -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);
} }

View File

@ -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;

View File

@ -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() {

View File

@ -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")

View File

@ -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();
} }

View File

@ -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);