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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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