Home | History | Annotate | Download | only in dexlib
      1 /*
      2  * [The "BSD licence"]
      3  * Copyright (c) 2010 Ben Gruver (JesusFreke)
      4  * All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. The name of the author may not be used to endorse or promote products
     15  *    derived from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 package org.jf.dexlib;
     30 
     31 import com.google.common.base.Preconditions;
     32 import org.jf.dexlib.Util.AlignmentUtils;
     33 import org.jf.dexlib.Util.AnnotatedOutput;
     34 import org.jf.dexlib.Util.ExceptionWithContext;
     35 import org.jf.dexlib.Util.Input;
     36 
     37 public abstract class Item<T extends Item> implements Comparable<T> {
     38     /**
     39      * The offset of this item in the dex file, or -1 if not known
     40      */
     41     protected int offset = -1;
     42 
     43     /**
     44      * The index of this item in the containing section, or -1 if not known
     45      */
     46     protected int index = -1;
     47 
     48     /**
     49      * The DexFile that this item is associatedr with
     50      */
     51     protected final DexFile dexFile;
     52 
     53     /**
     54      * The constructor that is used when reading in a <code>DexFile</code>
     55      * @param dexFile the <code>DexFile</code> that this item is associated with
     56      */
     57     protected Item(DexFile dexFile) {
     58         assert dexFile != null;
     59 
     60         this.dexFile = dexFile;
     61     }
     62 
     63     /**
     64      * Read in the item from the given input stream, and initialize the index
     65      * @param in the <code>Input</code> object to read from
     66      * @param index the index within the containing section of the item being read in
     67      * @param readContext a <code>ReadContext</code> object to hold information that is
     68      * only needed while reading in a file
     69      */
     70     protected void readFrom(Input in, int index, ReadContext readContext) {
     71         try {
     72             assert AlignmentUtils.isAligned(in.getCursor(), getItemType().ItemAlignment);
     73 
     74             this.offset = in.getCursor();
     75             this.index = index;
     76 
     77             this.readItem(in, readContext);
     78         } catch (Exception ex) {
     79             throw addExceptionContext(ex);
     80         }
     81     }
     82 
     83     /**
     84      * Place the item at the given offset and index, and return the offset of the byte following this item
     85      * @param offset The offset to place the item at
     86      * @param index The index of the item within the containing section
     87      * @return The offset of the byte following this item
     88      */
     89     protected int placeAt(int offset, int index) {
     90         try {
     91             assert AlignmentUtils.isAligned(offset, getItemType().ItemAlignment);
     92             assert !dexFile.getInplace() || (offset == this.offset && this.index == index);
     93 
     94             this.offset = offset;
     95             this.index = index;
     96             return this.placeItem(offset);
     97         } catch (Exception ex) {
     98             throw addExceptionContext(ex);
     99         }
    100     }
    101 
    102     /**
    103      * Write and annotate this item to the output stream
    104      * @param out The output stream to write and annotate to
    105      */
    106     protected void writeTo(AnnotatedOutput out) {
    107         try {
    108             assert AlignmentUtils.isAligned(offset, getItemType().ItemAlignment);
    109             //ensure that it is being written to the same offset where it was previously placed
    110             assert out.getCursor() == offset;
    111 
    112             if (out.annotates()) {
    113                 out.annotate(0, "[" + index + "] " + this.getItemType().TypeName);
    114             }
    115 
    116             out.indent();
    117             writeItem(out);
    118             out.deindent();
    119         } catch (Exception ex) {
    120             throw addExceptionContext(ex);
    121         }
    122     }
    123 
    124     /**
    125      * Returns a human readable form of this item
    126      * @return a human readable form of this item
    127      */
    128     public String toString() {
    129         return getConciseIdentity();
    130     }
    131 
    132     /**
    133      * The method in the concrete item subclass that actually reads in the data for the item
    134      *
    135      * The logic in this method can assume that the given Input object is valid and is
    136      * aligned as neccessary.
    137      *
    138      * This method is for internal use only
    139      * @param in the <code>Input</code> object to read from
    140      * @param readContext a <code>ReadContext</code> object to hold information that is
    141      * only needed while reading in a file
    142      */
    143     protected abstract void readItem(Input in, ReadContext readContext);
    144 
    145     /**
    146      * The method should finalize the layout of the item and return the offset of the byte
    147      * immediately following the item.
    148      *
    149      * The implementation of this method can assume that the offset argument has already been
    150      * aligned based on the item's alignment requirements
    151      *
    152      * This method is for internal use only
    153      * @param offset the (pre-aligned) offset to place the item at
    154      * @return the size of the item, in bytes
    155      */
    156     protected abstract int placeItem(int offset);
    157 
    158     /**
    159      * The method in the concrete item subclass that actually writes and annotates the data
    160      * for the item.
    161      *
    162      * The logic in this method can assume that the given Output object is valid and is
    163      * aligned as neccessary
    164      *
    165      * @param out The <code>AnnotatedOutput</code> object to write/annotate to
    166      */
    167     protected abstract void writeItem(AnnotatedOutput out);
    168 
    169     /**
    170      * This method is called to add item specific context information to an exception, to identify the "current item"
    171      * when the exception occured. It adds the value returned by <code>getConciseIdentity</code> as context for the
    172      * exception
    173      * @param ex The exception that occured
    174      * @return A RuntimeException with additional details about the item added
    175      */
    176     protected final RuntimeException addExceptionContext(Exception ex) {
    177         return ExceptionWithContext.withContext(ex, getConciseIdentity());
    178     }
    179 
    180     /**
    181      * @return An ItemType enum that represents the item type of this item
    182      */
    183     public abstract ItemType getItemType();
    184 
    185     /**
    186      * @return A concise (human-readable) string value that conveys the identity of this item
    187      */
    188     public abstract String getConciseIdentity();
    189 
    190 
    191     /**
    192      * Note that the item must have been placed before calling this method (See <code>DexFile.place()</code>)
    193      * @return the offset in the dex file where this item is located
    194      */
    195     public int getOffset() {
    196         Preconditions.checkState(offset != -1,
    197                 "The offset is not set until the DexFile containing this item is placed.");
    198         return offset;
    199     }
    200 
    201     /**
    202      * Note that the item must have been placed before calling this method (See <code>DexFile.place()</code>)
    203      * @return the index of this item within the item's containing section.
    204      */
    205     public int getIndex() {
    206         Preconditions.checkState(index != -1,
    207                 "The index is not set until the DexFile containing this item is placed.");
    208         return index;
    209     }
    210 
    211     /**
    212      * @return True if this item has been placed, otherwise False
    213      */
    214     public boolean isPlaced() {
    215         return offset != -1;
    216     }
    217 
    218     /**
    219      * @return the <code>DexFile</code> that contains this item
    220      */
    221     public DexFile getDexFile() {
    222         return dexFile;
    223     }
    224 }
    225