summaryrefslogtreecommitdiffstats
path: root/dexlib/src/main/java/org/jf/dexlib/Item.java
diff options
context:
space:
mode:
Diffstat (limited to 'dexlib/src/main/java/org/jf/dexlib/Item.java')
-rw-r--r--dexlib/src/main/java/org/jf/dexlib/Item.java224
1 files changed, 224 insertions, 0 deletions
diff --git a/dexlib/src/main/java/org/jf/dexlib/Item.java b/dexlib/src/main/java/org/jf/dexlib/Item.java
new file mode 100644
index 0000000..98c2338
--- /dev/null
+++ b/dexlib/src/main/java/org/jf/dexlib/Item.java
@@ -0,0 +1,224 @@
+/*
+ * [The "BSD licence"]
+ * Copyright (c) 2010 Ben Gruver (JesusFreke)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.jf.dexlib;
+
+import com.google.common.base.Preconditions;
+import org.jf.dexlib.Util.AlignmentUtils;
+import org.jf.dexlib.Util.AnnotatedOutput;
+import org.jf.dexlib.Util.ExceptionWithContext;
+import org.jf.dexlib.Util.Input;
+
+public abstract class Item<T extends Item> implements Comparable<T> {
+ /**
+ * The offset of this item in the dex file, or -1 if not known
+ */
+ protected int offset = -1;
+
+ /**
+ * The index of this item in the containing section, or -1 if not known
+ */
+ protected int index = -1;
+
+ /**
+ * The DexFile that this item is associatedr with
+ */
+ protected final DexFile dexFile;
+
+ /**
+ * The constructor that is used when reading in a <code>DexFile</code>
+ * @param dexFile the <code>DexFile</code> that this item is associated with
+ */
+ protected Item(DexFile dexFile) {
+ assert dexFile != null;
+
+ this.dexFile = dexFile;
+ }
+
+ /**
+ * Read in the item from the given input stream, and initialize the index
+ * @param in the <code>Input</code> object to read from
+ * @param index the index within the containing section of the item being read in
+ * @param readContext a <code>ReadContext</code> object to hold information that is
+ * only needed while reading in a file
+ */
+ protected void readFrom(Input in, int index, ReadContext readContext) {
+ try {
+ assert AlignmentUtils.isAligned(in.getCursor(), getItemType().ItemAlignment);
+
+ this.offset = in.getCursor();
+ this.index = index;
+
+ this.readItem(in, readContext);
+ } catch (Exception ex) {
+ throw addExceptionContext(ex);
+ }
+ }
+
+ /**
+ * Place the item at the given offset and index, and return the offset of the byte following this item
+ * @param offset The offset to place the item at
+ * @param index The index of the item within the containing section
+ * @return The offset of the byte following this item
+ */
+ protected int placeAt(int offset, int index) {
+ try {
+ assert AlignmentUtils.isAligned(offset, getItemType().ItemAlignment);
+ assert !dexFile.getInplace() || (offset == this.offset && this.index == index);
+
+ this.offset = offset;
+ this.index = index;
+ return this.placeItem(offset);
+ } catch (Exception ex) {
+ throw addExceptionContext(ex);
+ }
+ }
+
+ /**
+ * Write and annotate this item to the output stream
+ * @param out The output stream to write and annotate to
+ */
+ protected void writeTo(AnnotatedOutput out) {
+ try {
+ assert AlignmentUtils.isAligned(offset, getItemType().ItemAlignment);
+ //ensure that it is being written to the same offset where it was previously placed
+ assert out.getCursor() == offset;
+
+ if (out.annotates()) {
+ out.annotate(0, "[" + index + "] " + this.getItemType().TypeName);
+ }
+
+ out.indent();
+ writeItem(out);
+ out.deindent();
+ } catch (Exception ex) {
+ throw addExceptionContext(ex);
+ }
+ }
+
+ /**
+ * Returns a human readable form of this item
+ * @return a human readable form of this item
+ */
+ public String toString() {
+ return getConciseIdentity();
+ }
+
+ /**
+ * The method in the concrete item subclass that actually reads in the data for the item
+ *
+ * The logic in this method can assume that the given Input object is valid and is
+ * aligned as neccessary.
+ *
+ * This method is for internal use only
+ * @param in the <code>Input</code> object to read from
+ * @param readContext a <code>ReadContext</code> object to hold information that is
+ * only needed while reading in a file
+ */
+ protected abstract void readItem(Input in, ReadContext readContext);
+
+ /**
+ * The method should finalize the layout of the item and return the offset of the byte
+ * immediately following the item.
+ *
+ * The implementation of this method can assume that the offset argument has already been
+ * aligned based on the item's alignment requirements
+ *
+ * This method is for internal use only
+ * @param offset the (pre-aligned) offset to place the item at
+ * @return the size of the item, in bytes
+ */
+ protected abstract int placeItem(int offset);
+
+ /**
+ * The method in the concrete item subclass that actually writes and annotates the data
+ * for the item.
+ *
+ * The logic in this method can assume that the given Output object is valid and is
+ * aligned as neccessary
+ *
+ * @param out The <code>AnnotatedOutput</code> object to write/annotate to
+ */
+ protected abstract void writeItem(AnnotatedOutput out);
+
+ /**
+ * This method is called to add item specific context information to an exception, to identify the "current item"
+ * when the exception occured. It adds the value returned by <code>getConciseIdentity</code> as context for the
+ * exception
+ * @param ex The exception that occured
+ * @return A RuntimeException with additional details about the item added
+ */
+ protected final RuntimeException addExceptionContext(Exception ex) {
+ return ExceptionWithContext.withContext(ex, getConciseIdentity());
+ }
+
+ /**
+ * @return An ItemType enum that represents the item type of this item
+ */
+ public abstract ItemType getItemType();
+
+ /**
+ * @return A concise (human-readable) string value that conveys the identity of this item
+ */
+ public abstract String getConciseIdentity();
+
+
+ /**
+ * Note that the item must have been placed before calling this method (See <code>DexFile.place()</code>)
+ * @return the offset in the dex file where this item is located
+ */
+ public int getOffset() {
+ Preconditions.checkState(offset != -1,
+ "The offset is not set until the DexFile containing this item is placed.");
+ return offset;
+ }
+
+ /**
+ * Note that the item must have been placed before calling this method (See <code>DexFile.place()</code>)
+ * @return the index of this item within the item's containing section.
+ */
+ public int getIndex() {
+ Preconditions.checkState(index != -1,
+ "The index is not set until the DexFile containing this item is placed.");
+ return index;
+ }
+
+ /**
+ * @return True if this item has been placed, otherwise False
+ */
+ public boolean isPlaced() {
+ return offset != -1;
+ }
+
+ /**
+ * @return the <code>DexFile</code> that contains this item
+ */
+ public DexFile getDexFile() {
+ return dexFile;
+ }
+}