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>
|
||||
<version>0.91-SNAPSHOT</version>
|
||||
</parent>
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
|
@ -54,7 +54,7 @@ public class AnnotationDirectoryItem extends OffsettedItem<AnnotationDirectoryIt
|
||||
private ClassDefItem parent = null;
|
||||
|
||||
protected AnnotationDirectoryItem(final DexFile dexFile, int offset) {
|
||||
super(offset);
|
||||
super(dexFile, offset);
|
||||
|
||||
fields = new Field[] {
|
||||
classAnnotationsReferenceField = new OffsettedItemReference<AnnotationSetItem>(
|
||||
|
@ -35,7 +35,7 @@ public class AnnotationItem extends OffsettedItem<AnnotationItem> {
|
||||
private final AnnotationEncodedValueSubField annotationField;
|
||||
|
||||
public AnnotationItem(DexFile dexFile, int offset) {
|
||||
super(offset);
|
||||
super(dexFile, offset);
|
||||
|
||||
fields = new Field[] {
|
||||
visibilityField = new ByteField("visibility"),
|
||||
@ -45,7 +45,7 @@ public class AnnotationItem extends OffsettedItem<AnnotationItem> {
|
||||
|
||||
public AnnotationItem(DexFile dexFile, AnnotationVisibility visibility,
|
||||
AnnotationEncodedValueSubField annotation) {
|
||||
super(-1);
|
||||
super(dexFile, -1);
|
||||
|
||||
fields = new Field[] {
|
||||
this.visibilityField = new ByteField(visibility.value, "visibility"),
|
||||
|
@ -39,7 +39,7 @@ public class AnnotationSetItem extends OffsettedItem<AnnotationSetItem> {
|
||||
private final FieldListField<OffsettedItemReference<AnnotationItem>> annotationsListField;
|
||||
|
||||
public AnnotationSetItem(final DexFile dexFile, int offset) {
|
||||
super(offset);
|
||||
super(dexFile, offset);
|
||||
|
||||
fields = new Field[] {
|
||||
annotationCountField = new ListSizeField(annotationReferences, new IntegerField("size")),
|
||||
|
@ -39,7 +39,7 @@ public class AnnotationSetRefList extends OffsettedItem<AnnotationSetRefList> {
|
||||
private final FieldListField<OffsettedItemReference<AnnotationSetItem>> annotationSetsListField;
|
||||
|
||||
public AnnotationSetRefList(final DexFile dexFile, int offset) {
|
||||
super(offset);
|
||||
super(dexFile, offset);
|
||||
|
||||
fields = new Field[] {
|
||||
annotationSetCountField = new ListSizeField(annotationSetReferences, new IntegerField("size")),
|
||||
|
@ -52,7 +52,7 @@ public class ClassDataItem extends OffsettedItem<ClassDataItem> {
|
||||
private ClassDefItem parent = null;
|
||||
|
||||
public ClassDataItem(final DexFile dexFile, int offset) {
|
||||
super(offset);
|
||||
super(dexFile, offset);
|
||||
|
||||
fields = new Field[] {
|
||||
staticFieldsCountField = new ListSizeField(staticFieldList,
|
||||
|
@ -50,7 +50,7 @@ public class ClassDefItem extends IndexedItem<ClassDefItem> {
|
||||
private final DexFile dexFile;
|
||||
|
||||
public ClassDefItem(DexFile dexFile, int index) {
|
||||
super(index);
|
||||
super(dexFile, index);
|
||||
|
||||
this.dexFile = dexFile;
|
||||
|
||||
|
@ -161,16 +161,16 @@ public abstract class Instruction {
|
||||
if (referencedItem != null) {
|
||||
switch (opcode.referenceType) {
|
||||
case string:
|
||||
clone.referencedItem = dexFile.StringIdsSection.intern(dexFile, (StringIdItem)referencedItem);
|
||||
clone.referencedItem = dexFile.StringIdsSection.intern((StringIdItem)referencedItem);
|
||||
break;
|
||||
case type:
|
||||
clone.referencedItem = dexFile.TypeIdsSection.intern(dexFile, (TypeIdItem)referencedItem);
|
||||
clone.referencedItem = dexFile.TypeIdsSection.intern((TypeIdItem)referencedItem);
|
||||
break;
|
||||
case field:
|
||||
clone.referencedItem = dexFile.FieldIdsSection.intern(dexFile, (FieldIdItem)referencedItem);
|
||||
clone.referencedItem = dexFile.FieldIdsSection.intern((FieldIdItem)referencedItem);
|
||||
break;
|
||||
case method:
|
||||
clone.referencedItem = dexFile.MethodIdsSection.intern(dexFile, (MethodIdItem)referencedItem);
|
||||
clone.referencedItem = dexFile.MethodIdsSection.intern((MethodIdItem)referencedItem);
|
||||
break;
|
||||
case none:
|
||||
break;
|
||||
|
@ -57,7 +57,7 @@ public class CodeItem extends OffsettedItem<CodeItem> {
|
||||
private MethodIdItem parent = null;
|
||||
|
||||
public CodeItem(final DexFile dexFile, int offset) {
|
||||
super(offset);
|
||||
super(dexFile, offset);
|
||||
|
||||
instructionList = new ArrayList<InstructionField>();
|
||||
|
||||
|
@ -57,7 +57,7 @@ public abstract class DebugInstructionFactory {
|
||||
case 0x05:
|
||||
return new EndLocal();
|
||||
case 0x06:
|
||||
return new RestartLocal(dexFile.isForDumping());
|
||||
return new RestartLocal(dexFile);
|
||||
case 0x07:
|
||||
return new SetPrologueEnd();
|
||||
case 0x08:
|
||||
|
@ -34,18 +34,23 @@ public class RestartLocal extends CompositeField<RestartLocal> implements DebugI
|
||||
private final ByteField opcode;
|
||||
private final Leb128Field registerNumber;
|
||||
|
||||
public RestartLocal(boolean forDumping) {
|
||||
public RestartLocal(DexFile dexFile) {
|
||||
super("DBG_RESTART_LOCAL");
|
||||
fields = new Field[] {
|
||||
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")
|
||||
};
|
||||
}
|
||||
|
||||
public RestartLocal(int registerNumber) {
|
||||
this(false);
|
||||
this.registerNumber.cacheValue(registerNumber);
|
||||
super("DBG_RESTART_LOCAL");
|
||||
fields = new Field[] {
|
||||
this.opcode = new ByteField((byte)0x06, "opcode"),
|
||||
this.registerNumber = new Leb128Field(registerNumber, "register_num")
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
public byte getOpcode() {
|
||||
|
@ -40,7 +40,7 @@ public class StartLocal extends CompositeField<StartLocal> implements DebugInstr
|
||||
super("DBG_START_LOCAL");
|
||||
fields = new Field[] {
|
||||
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"),
|
||||
localName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||
new Leb128p1Field(null), "name_idx"),
|
||||
|
@ -41,7 +41,7 @@ public class StartLocalExtended extends CompositeField<StartLocalExtended> imple
|
||||
super("DBG_START_LOCAL_EXTENDED");
|
||||
fields = new Field[] {
|
||||
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"),
|
||||
localName = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||
new Leb128p1Field(null), "name_idx"),
|
||||
|
@ -52,7 +52,7 @@ public class DebugInfoItem extends OffsettedItem<DebugInfoItem> {
|
||||
private CodeItem parent = null;
|
||||
|
||||
public DebugInfoItem(final DexFile dexFile, int offset) {
|
||||
super(offset);
|
||||
super(dexFile, offset);
|
||||
|
||||
fields = new Field[] {
|
||||
lineStartField = new Leb128Field("line_start"),
|
||||
|
@ -38,22 +38,140 @@ import java.security.DigestException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
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
|
||||
{
|
||||
/**
|
||||
* A mapping from ItemType to the section that contains items of the given type
|
||||
*/
|
||||
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 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 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.put(ItemType.TYPE_ANNOTATION_ITEM, AnnotationsSection);
|
||||
@ -98,21 +216,54 @@ public class DexFile
|
||||
};
|
||||
}
|
||||
|
||||
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();
|
||||
Input in = new ByteArrayInput(FileUtils.readFile(file));
|
||||
/**
|
||||
* 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
|
||||
* <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);
|
||||
HeaderItem headerItem = HeaderItemSection.items.get(0);
|
||||
|
||||
in.setCursor(headerItem.getMapOffset());
|
||||
|
||||
MapSection.readFrom(1, in);
|
||||
|
||||
MapField[] mapEntries = MapSection.items.get(0).getMapEntries();
|
||||
@ -121,6 +272,11 @@ public class DexFile
|
||||
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[] {
|
||||
ItemType.TYPE_HEADER_ITEM.getMapValue(),
|
||||
ItemType.TYPE_STRING_ID_ITEM.getMapValue(),
|
||||
@ -147,64 +303,169 @@ public class DexFile
|
||||
if (mapField != null) {
|
||||
Section section = sectionsByType.get(mapField.getSectionItemType());
|
||||
if (section != null) {
|
||||
in.setCursor(mapField.getSectionOffset());
|
||||
section.readFrom(mapField.getSectionSize(), in);
|
||||
in.setCursor(mapField.getCachedSectionOffset());
|
||||
section.readFrom(mapField.getCachedSectionSize(), in);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static DexFile makeBlankDexFile() {
|
||||
DexFile dexFile = new DexFile();
|
||||
try
|
||||
{
|
||||
dexFile.HeaderItemSection.intern(dexFile, new HeaderItem(dexFile, 0));
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
/**
|
||||
* Constructs a new, blank dex file. Classes can be added to this dex file by calling
|
||||
* the <code>Section.intern()</code> method of <code>ClassDefsSection</code>
|
||||
*/
|
||||
public DexFile() {
|
||||
this(true);
|
||||
|
||||
dexFile.MapSection.intern(dexFile, MapItem.makeBlankMapItem(dexFile));
|
||||
return dexFile;
|
||||
HeaderItemSection.intern(new HeaderItem(dexFile, 0));
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
offset = indexedSection.place(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) {
|
||||
if (sort) {
|
||||
if (this.sortAllItems && !this.inplace) {
|
||||
offsettedSection.sortSection();
|
||||
}
|
||||
offset = offsettedSection.place(offset);
|
||||
@ -212,12 +473,26 @@ public class DexFile
|
||||
|
||||
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) {
|
||||
HeaderItemSection.writeTo(out);
|
||||
|
||||
for (IndexedSection indexedSection: indexedSections) {
|
||||
indexedSection.writeTo(out);
|
||||
}
|
||||
@ -229,48 +504,74 @@ public class DexFile
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
return new ClassDefItem(dexFile, index);
|
||||
}
|
||||
|
||||
public int place(int offset) {
|
||||
if (dexFile.getInplace()) {
|
||||
return super.place(offset);
|
||||
}
|
||||
|
||||
int ret = ClassDefItem.placeClassDefItems(this, offset);
|
||||
|
||||
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) {
|
||||
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) {
|
||||
return new TypeListItem(dexFile, offset);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The <code>OffsettedSection</code> containing <code>AnnotationSetRefList</code> items
|
||||
*/
|
||||
public final OffsettedSection<AnnotationSetRefList> AnnotationSetRefListsSection =
|
||||
new OffsettedSection<AnnotationSetRefList>() {
|
||||
new OffsettedSection<AnnotationSetRefList>(this) {
|
||||
protected AnnotationSetRefList make(int offset) {
|
||||
return new AnnotationSetRefList(dexFile, offset);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The <code>OffsettedSection</code> containing <code>AnnotationSetItem</code> items
|
||||
*/
|
||||
public final OffsettedSection<AnnotationSetItem> AnnotationSetsSection =
|
||||
new OffsettedSection<AnnotationSetItem>() {
|
||||
new OffsettedSection<AnnotationSetItem>(this) {
|
||||
protected AnnotationSetItem make(int 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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
return new EncodedArrayItem(dexFile, offset);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* The <code>OffsettedSection</code> containing <code>AnnotationDirectoryItem</code> items
|
||||
*/
|
||||
public final OffsettedSection<AnnotationDirectoryItem> AnnotationDirectoriesSection =
|
||||
new OffsettedSection<AnnotationDirectoryItem>() {
|
||||
new OffsettedSection<AnnotationDirectoryItem>(this) {
|
||||
protected AnnotationDirectoryItem make(int offset) {
|
||||
return new AnnotationDirectoryItem(dexFile, offset);
|
||||
}
|
||||
@ -354,8 +689,9 @@ public class DexFile
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the signature for the <code>.dex</code> file in the
|
||||
* given array, and modify the array to contain it.
|
||||
* Calculates the signature for the dex file in the given byte array,
|
||||
* 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
|
||||
*/
|
||||
|
@ -37,7 +37,7 @@ public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> {
|
||||
private final ArrayEncodedValueSubField encodedArray;
|
||||
|
||||
public EncodedArrayItem(DexFile dexFile, int offset) {
|
||||
super(offset);
|
||||
super(dexFile, offset);
|
||||
|
||||
fields = new Field[] {
|
||||
encodedArray = new ArrayEncodedValueSubField(dexFile)
|
||||
@ -45,7 +45,7 @@ public class EncodedArrayItem extends OffsettedItem<EncodedArrayItem> {
|
||||
}
|
||||
|
||||
public EncodedArrayItem(DexFile dexFile, ArrayList<EncodedValue> encodedValues) {
|
||||
super(0);
|
||||
super(dexFile, 0);
|
||||
|
||||
fields = new Field[] {
|
||||
encodedArray = new ArrayEncodedValueSubField(dexFile, encodedValues)
|
||||
|
@ -100,8 +100,7 @@ public class EncodedIndexedItemReference<T extends IndexedItem<T>>
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
T copiedItem = copy.section.intern(dexFile, item);
|
||||
copy.item = copiedItem;
|
||||
copy.item = copy.section.intern(item);
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
|
@ -34,7 +34,7 @@ public class FieldIdItem extends IndexedItem<FieldIdItem> {
|
||||
private final IndexedItemReference<StringIdItem> fieldNameReferenceField;
|
||||
|
||||
public FieldIdItem(DexFile dexFile, int index) {
|
||||
super(index);
|
||||
super(dexFile, index);
|
||||
fields = new Field[] {
|
||||
classTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||
new ShortIntegerField(null), "class_idx"),
|
||||
|
@ -63,8 +63,8 @@ public class HeaderItem extends IndexedItem<HeaderItem> {
|
||||
private final IntegerField dataSizeField;
|
||||
private final IntegerField dataOffField;
|
||||
|
||||
public HeaderItem(final DexFile file, int index) {
|
||||
super(index);
|
||||
public HeaderItem(final DexFile dexFile, int index) {
|
||||
super(dexFile, index);
|
||||
|
||||
try
|
||||
{
|
||||
@ -84,64 +84,49 @@ public class HeaderItem extends IndexedItem<HeaderItem> {
|
||||
super.writeTo(out);
|
||||
}
|
||||
},
|
||||
fileSizeField = new IntegerField("file_size") {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
cacheValue(file.getFileSize());
|
||||
super.writeTo(out);
|
||||
}
|
||||
},
|
||||
fileSizeField = new IntegerField("file_size"),
|
||||
headerSizeField = new IntegerField(HEADER_SIZE,"header_size"),
|
||||
endianTagField = new IntegerField(ENDIAN_TAG,"endian_tag"),
|
||||
linkSizeField = new IntegerField(0,"link_size"),
|
||||
linkOffField = new IntegerField(0,"link_off"),
|
||||
mapOffField = new IntegerField("map_off") {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
cacheValue(file.MapSection.getOffset());
|
||||
cacheValue(dexFile.MapSection.getOffset());
|
||||
super.writeTo(out);
|
||||
}
|
||||
},
|
||||
StringIdsHeaderField = new SectionHeaderInfo("string_ids") {
|
||||
protected Section getSection() {
|
||||
return file.StringIdsSection;
|
||||
return dexFile.StringIdsSection;
|
||||
}
|
||||
},
|
||||
TypeIdsHeaderField = new SectionHeaderInfo("type_ids") {
|
||||
protected Section getSection() {
|
||||
return file.TypeIdsSection;
|
||||
return dexFile.TypeIdsSection;
|
||||
}
|
||||
},
|
||||
ProtoIdsHeaderField = new SectionHeaderInfo("proto_ids") {
|
||||
protected Section getSection() {
|
||||
return file.ProtoIdsSection;
|
||||
return dexFile.ProtoIdsSection;
|
||||
}
|
||||
},
|
||||
FieldIdsHeaderField = new SectionHeaderInfo("field_ids") {
|
||||
protected Section getSection() {
|
||||
return file.FieldIdsSection;
|
||||
return dexFile.FieldIdsSection;
|
||||
}
|
||||
},
|
||||
MethodIdsHeaderField = new SectionHeaderInfo("method_ids") {
|
||||
protected Section getSection() {
|
||||
return file.MethodIdsSection;
|
||||
return dexFile.MethodIdsSection;
|
||||
}
|
||||
},
|
||||
ClassDefsHeaderField = new SectionHeaderInfo("class_defs") {
|
||||
protected Section getSection() {
|
||||
return file.ClassDefsSection;
|
||||
return dexFile.ClassDefsSection;
|
||||
}
|
||||
},
|
||||
dataSizeField = new IntegerField("data_size") {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
cacheValue(file.getDataSize());
|
||||
super.writeTo(out);
|
||||
}
|
||||
},
|
||||
dataOffField = new IntegerField("data_off") {
|
||||
public void writeTo(AnnotatedOutput out) {
|
||||
cacheValue(file.getDataOffset());
|
||||
super.writeTo(out);
|
||||
}
|
||||
}
|
||||
dataSizeField = new IntegerField("data_size"),
|
||||
dataOffField = new IntegerField("data_off")
|
||||
};
|
||||
} catch (UnsupportedEncodingException 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
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@ -33,7 +33,8 @@ import org.jf.dexlib.Util.Input;
|
||||
import java.util.Collections;
|
||||
|
||||
public abstract class IndexedSection<T extends IndexedItem<T>> extends Section<T> {
|
||||
public IndexedSection() {
|
||||
public IndexedSection(DexFile dexFile) {
|
||||
super(dexFile);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
public T intern(DexFile dexFile, T item) {
|
||||
public T intern(T item) {
|
||||
T itemToReturn = getInternedItem(item);
|
||||
|
||||
if (itemToReturn == null) {
|
||||
@ -78,7 +79,9 @@ public abstract class IndexedSection<T extends IndexedItem<T>> extends Section<T
|
||||
}
|
||||
|
||||
public int place(int offset) {
|
||||
sortSection();
|
||||
if (!dexFile.getInplace()) {
|
||||
sortSection();
|
||||
}
|
||||
|
||||
return super.place(offset);
|
||||
}
|
||||
|
@ -34,10 +34,12 @@ import org.jf.dexlib.Util.Input;
|
||||
public abstract class Item<T extends Item> implements Comparable<T> {
|
||||
protected int offset = -1;
|
||||
protected int index = -1;
|
||||
protected final DexFile dexFile;
|
||||
|
||||
protected Field[] fields;
|
||||
|
||||
protected Item() {
|
||||
protected Item(DexFile dexFile) {
|
||||
this.dexFile = dexFile;
|
||||
}
|
||||
|
||||
public boolean isPlaced() {
|
||||
|
@ -70,7 +70,7 @@ public abstract class ItemReference<T extends Item<T>, S extends ItemReference<T
|
||||
return;
|
||||
}
|
||||
Section<T> section = copy.getSection();
|
||||
T copiedItem = section.intern(dexFile, referencedItem);
|
||||
T copiedItem = section.intern(referencedItem);
|
||||
copy.setReference(copiedItem);
|
||||
}
|
||||
|
||||
|
@ -30,15 +30,14 @@ package org.jf.dexlib;
|
||||
|
||||
public class MapField extends CompositeField<MapField> {
|
||||
private final ShortIntegerField sectionTypeField;
|
||||
private final ShortIntegerField unusedField;
|
||||
private final SectionHeaderInfo sectionInfoField;
|
||||
|
||||
public MapField(final DexFile dexFile) {
|
||||
protected MapField(final DexFile dexFile) {
|
||||
super("map_entry");
|
||||
fields = new Field[] {
|
||||
//TODO: add an annotation for the item type
|
||||
sectionTypeField = new ShortIntegerField("type"),
|
||||
unusedField = new ShortIntegerField((short)0, "not used"),
|
||||
new ShortIntegerField((short)0, "padding"),
|
||||
sectionInfoField = new SectionHeaderInfo("section") {
|
||||
protected Section getSection() {
|
||||
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);
|
||||
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() {
|
||||
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() {
|
||||
Section s;
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -35,8 +35,8 @@ import java.util.Comparator;
|
||||
public class MapItem extends IndexedItem<MapItem> {
|
||||
private ArrayList<MapField> mapEntries = new ArrayList<MapField>();
|
||||
|
||||
public MapItem(final DexFile dexFile, int index) {
|
||||
super(index);
|
||||
protected MapItem(final DexFile dexFile, int index) {
|
||||
super(dexFile, index);
|
||||
|
||||
fields = new Field[] {
|
||||
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) {
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
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() {
|
||||
return mapEntries.toArray(new MapField[1]);
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ public class MethodIdItem extends IndexedItem<MethodIdItem> {
|
||||
private final IndexedItemReference<StringIdItem> methodNameReferenceField;
|
||||
|
||||
public MethodIdItem(DexFile dexFile, int index) {
|
||||
super(index);
|
||||
super(dexFile, index);
|
||||
fields = new Field[] {
|
||||
classTypeReferenceField = new IndexedItemReference<TypeIdItem>(dexFile.TypeIdsSection,
|
||||
new ShortIntegerField(null), "class_idx"),
|
||||
|
@ -29,7 +29,8 @@
|
||||
package org.jf.dexlib;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,8 @@ import java.util.Comparator;
|
||||
public abstract class OffsettedSection<T extends OffsettedItem<T>> extends Section<T> {
|
||||
protected HashMap<Integer, T> itemsByOffset;
|
||||
|
||||
public OffsettedSection() {
|
||||
public OffsettedSection(DexFile dexFile) {
|
||||
super(dexFile);
|
||||
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);
|
||||
|
||||
public T intern(DexFile dexFile, T item) {
|
||||
public T intern(T item) {
|
||||
T itemToReturn = getInternedItem(item);
|
||||
|
||||
if (itemToReturn == null) {
|
||||
|
@ -36,7 +36,7 @@ public class ProtoIdItem extends IndexedItem<ProtoIdItem> {
|
||||
private final OffsettedItemReference<TypeListItem> parametersReferenceField;
|
||||
|
||||
public ProtoIdItem(DexFile dexFile, int index) {
|
||||
super(index);
|
||||
super(dexFile, index);
|
||||
fields = new Field[] {
|
||||
shortyDescriptorReferenceField = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||
new IntegerField(null), "shorty_idx"),
|
||||
@ -88,7 +88,7 @@ public class ProtoIdItem extends IndexedItem<ProtoIdItem> {
|
||||
if (typeList == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return typeList.getCount();
|
||||
return typeList.getTypeCount();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,8 +37,9 @@ import java.util.List;
|
||||
import java.util.Collections;
|
||||
|
||||
public abstract class Section<T extends Item> {
|
||||
protected ArrayList<T> items;
|
||||
protected final ArrayList<T> items;
|
||||
protected HashMap<T, T> uniqueItems = null;
|
||||
protected final DexFile dexFile;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
public Section() {
|
||||
public Section(DexFile dexFile) {
|
||||
this.dexFile = dexFile;
|
||||
items = new ArrayList<T>();
|
||||
}
|
||||
|
||||
@ -136,5 +138,5 @@ public abstract class Section<T extends Item> {
|
||||
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 NullTerminatedByteArrayField stringByteArray;
|
||||
|
||||
public StringDataItem(int offset) {
|
||||
super(offset);
|
||||
public StringDataItem(DexFile dexFile, int offset) {
|
||||
super(dexFile, offset);
|
||||
|
||||
fields = new Field[] {
|
||||
stringSize = new Leb128Field("string_length"),
|
||||
@ -46,8 +46,8 @@ public class StringDataItem extends OffsettedItem<StringDataItem> implements Com
|
||||
};
|
||||
}
|
||||
|
||||
public StringDataItem(String value) {
|
||||
super(-1);
|
||||
public StringDataItem(DexFile dexFile, String value) {
|
||||
super(dexFile, -1);
|
||||
|
||||
this.value = value;
|
||||
|
||||
|
@ -34,7 +34,7 @@ public class StringIdItem extends IndexedItem<StringIdItem> {
|
||||
private final OffsettedItemReference<StringDataItem> stringDataReferenceField;
|
||||
|
||||
public StringIdItem(DexFile dexFile, int index) {
|
||||
super(index);
|
||||
super(dexFile, index);
|
||||
fields = new Field[] {
|
||||
stringDataReferenceField = new OffsettedItemReference<StringDataItem>(dexFile.StringDataSection,
|
||||
new IntegerField(null), "string_data_off")
|
||||
@ -47,7 +47,7 @@ public class StringIdItem extends IndexedItem<StringIdItem> {
|
||||
}
|
||||
|
||||
public StringIdItem(DexFile dexFile, String value) {
|
||||
this(dexFile, new StringDataItem(value));
|
||||
this(dexFile, new StringDataItem(dexFile, value));
|
||||
}
|
||||
|
||||
protected int getAlignment() {
|
||||
|
@ -32,7 +32,7 @@ public class TypeIdItem extends IndexedItem<TypeIdItem> {
|
||||
private final IndexedItemReference<StringIdItem> typeDescriptorReferenceField;
|
||||
|
||||
public TypeIdItem(DexFile dexFile, int index) {
|
||||
super(index);
|
||||
super(dexFile, index);
|
||||
fields = new Field[] {
|
||||
typeDescriptorReferenceField = new IndexedItemReference<StringIdItem>(dexFile.StringIdsSection,
|
||||
new IntegerField(null), "descriptor_idx")
|
||||
|
@ -34,14 +34,13 @@ import java.util.List;
|
||||
public class TypeListItem extends OffsettedItem<TypeListItem> {
|
||||
private final ArrayList<IndexedItemReference<TypeIdItem>> typeList = new ArrayList<IndexedItemReference<TypeIdItem>>();
|
||||
|
||||
private final ListSizeField sizeField;
|
||||
private final FieldListField<IndexedItemReference<TypeIdItem>> listField;
|
||||
|
||||
public TypeListItem(final DexFile dexFile, int offset) {
|
||||
super(offset);
|
||||
super(dexFile, offset);
|
||||
|
||||
fields = new Field[] {
|
||||
sizeField = new ListSizeField(typeList, new IntegerField("size")),
|
||||
new ListSizeField(typeList, new IntegerField("size")),
|
||||
listField = new FieldListField<IndexedItemReference<TypeIdItem>>(typeList, "type_item") {
|
||||
protected IndexedItemReference<TypeIdItem> make() {
|
||||
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() {
|
||||
ArrayList<TypeIdItem> list = new ArrayList<TypeIdItem>(typeList.size());
|
||||
|
||||
@ -80,7 +80,7 @@ public class TypeListItem extends OffsettedItem<TypeListItem> {
|
||||
return wordCount;
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
public int getTypeCount() {
|
||||
return typeList.size();
|
||||
}
|
||||
|
||||
|
@ -82,7 +82,7 @@ public class TryListBuilderTest
|
||||
public void singleTryTest() {
|
||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||
|
||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
||||
DexFile dexFile = new DexFile();
|
||||
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
|
||||
tryListBuilder.addHandler(typeIdItem, 2, 5, 100);
|
||||
|
||||
@ -98,7 +98,7 @@ public class TryListBuilderTest
|
||||
public void singleTryWithCatchAllTest() {
|
||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||
|
||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
||||
DexFile dexFile = new DexFile();
|
||||
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
|
||||
tryListBuilder.addHandler(typeIdItem, 2, 5, 100);
|
||||
|
||||
@ -117,7 +117,7 @@ public class TryListBuilderTest
|
||||
// |-----|
|
||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||
|
||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
||||
DexFile dexFile = new DexFile();
|
||||
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
|
||||
tryListBuilder.addHandler(typeIdItem, 2, 5, 100);
|
||||
|
||||
@ -138,7 +138,7 @@ public class TryListBuilderTest
|
||||
// |-----|
|
||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||
|
||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
||||
DexFile dexFile = new DexFile();
|
||||
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
|
||||
tryListBuilder.addHandler(typeIdItem, 2, 5, 100);
|
||||
|
||||
@ -159,7 +159,7 @@ public class TryListBuilderTest
|
||||
//|-----|
|
||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||
|
||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
||||
DexFile dexFile = new DexFile();
|
||||
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
|
||||
tryListBuilder.addHandler(typeIdItem, 5, 10, 101);
|
||||
tryListBuilder.addHandler(typeIdItem, 2, 5, 100);
|
||||
@ -179,7 +179,7 @@ public class TryListBuilderTest
|
||||
//|-----|
|
||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||
|
||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
||||
DexFile dexFile = new DexFile();
|
||||
TypeIdItem typeIdItem = new TypeIdItem(dexFile, "Ljava/lang/Exception;");
|
||||
|
||||
tryListBuilder.addHandler(typeIdItem, 10, 15, 101);
|
||||
@ -201,7 +201,7 @@ public class TryListBuilderTest
|
||||
//|-----|
|
||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||
|
||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
||||
DexFile dexFile = new DexFile();
|
||||
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
||||
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
||||
|
||||
@ -221,7 +221,7 @@ public class TryListBuilderTest
|
||||
// |-----|
|
||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||
|
||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
||||
DexFile dexFile = new DexFile();
|
||||
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
||||
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
||||
|
||||
@ -245,7 +245,7 @@ public class TryListBuilderTest
|
||||
//|-----|
|
||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||
|
||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
||||
DexFile dexFile = new DexFile();
|
||||
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
||||
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
||||
|
||||
@ -268,7 +268,7 @@ public class TryListBuilderTest
|
||||
// |---|
|
||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||
|
||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
||||
DexFile dexFile = new DexFile();
|
||||
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
||||
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
||||
|
||||
@ -291,7 +291,7 @@ public class TryListBuilderTest
|
||||
//|-----|
|
||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||
|
||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
||||
DexFile dexFile = new DexFile();
|
||||
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
||||
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
||||
|
||||
@ -314,7 +314,7 @@ public class TryListBuilderTest
|
||||
//|---|
|
||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||
|
||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
||||
DexFile dexFile = new DexFile();
|
||||
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
||||
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
||||
|
||||
@ -336,7 +336,7 @@ public class TryListBuilderTest
|
||||
//|-----|
|
||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||
|
||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
||||
DexFile dexFile = new DexFile();
|
||||
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
||||
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
||||
|
||||
@ -358,7 +358,7 @@ public class TryListBuilderTest
|
||||
// |---|
|
||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||
|
||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
||||
DexFile dexFile = new DexFile();
|
||||
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
||||
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
||||
|
||||
@ -380,7 +380,7 @@ public class TryListBuilderTest
|
||||
//|-----|
|
||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||
|
||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
||||
DexFile dexFile = new DexFile();
|
||||
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
||||
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
||||
|
||||
@ -404,7 +404,7 @@ public class TryListBuilderTest
|
||||
//|--------------------|
|
||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||
|
||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
||||
DexFile dexFile = new DexFile();
|
||||
TypeIdItem typeIdItem1 = new TypeIdItem(dexFile, "Ljava/lang/Exception1;");
|
||||
TypeIdItem typeIdItem2 = new TypeIdItem(dexFile, "Ljava/lang/Exception2;");
|
||||
TypeIdItem typeIdItem3= new TypeIdItem(dexFile, "Ljava/lang/Exception3;");
|
||||
@ -434,7 +434,7 @@ public class TryListBuilderTest
|
||||
// |---|
|
||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||
|
||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
||||
DexFile dexFile = new DexFile();
|
||||
|
||||
tryListBuilder.addCatchAllHandler(2, 8, 100);
|
||||
tryListBuilder.addCatchAllHandler(4, 6, 101);
|
||||
@ -454,7 +454,7 @@ public class TryListBuilderTest
|
||||
//|-----|
|
||||
TryListBuilder tryListBuilder = new TryListBuilder();
|
||||
|
||||
DexFile dexFile = DexFile.makeBlankDexFile();
|
||||
DexFile dexFile = new DexFile();
|
||||
|
||||
tryListBuilder.addCatchAllHandler(4, 6, 100);
|
||||
tryListBuilder.addCatchAllHandler(2, 8, 101);
|
||||
|
Loading…
x
Reference in New Issue
Block a user