diff options
Diffstat (limited to 'dexlib/src/main/java/org/jf/dexlib/Item.java')
-rw-r--r-- | dexlib/src/main/java/org/jf/dexlib/Item.java | 224 |
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; + } +} |