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 org.jf.dexlib.Util.AlignmentUtils;
     32 import org.jf.dexlib.Util.AnnotatedOutput;
     33 import org.jf.dexlib.Util.Input;
     34 
     35 import java.util.ArrayList;
     36 import java.util.Collections;
     37 import java.util.HashMap;
     38 import java.util.List;
     39 
     40 public abstract class Section<T extends Item> {
     41     /**
     42      * A list of the items that this section contains.
     43      * If the section has been placed, this list should be in the order that the items
     44      * will written to the dex file
     45      */
     46     protected final ArrayList<T> items;
     47 
     48     /**
     49      * A HashMap of the items in this section. This is used when interning items, to determine
     50      * if this section already has an item equivalent to the one that is being interned.
     51      * Both the key and the value should be the same object
     52      */
     53     protected HashMap<T,T> uniqueItems = null;
     54 
     55     /**
     56      * The offset of this section within the <code>DexFile</code>
     57      */
     58     protected int offset = 0;
     59 
     60     /**
     61      * The type of item that this section holds
     62      */
     63     public final ItemType ItemType;
     64 
     65     /**
     66      * The <code>DexFile</code> that this section belongs to
     67      */
     68     public final DexFile DexFile;
     69 
     70     /**
     71      * Create a new section
     72      * @param dexFile The <code>DexFile</code> that this section belongs to
     73      * @param itemType The itemType that this section will hold
     74      */
     75     protected Section(DexFile dexFile, ItemType itemType) {
     76         this.DexFile = dexFile;
     77         items = new ArrayList<T>();
     78         this.ItemType = itemType;
     79     }
     80 
     81     /**
     82      * Finalize the location of all items, and place them starting at the given offset
     83      * @param offset The offset where this section should be placed
     84      * @return the offset of the byte immediate after the last item in this section
     85      */
     86     protected int placeAt(int offset) {
     87         if (items.size() > 0) {
     88             offset = AlignmentUtils.alignOffset(offset, ItemType.ItemAlignment);
     89             assert !DexFile.getInplace() || offset == this.offset;
     90             this.offset = offset;
     91 
     92             for (int i=0; i < items.size(); i++) {
     93                 T item = items.get(i);
     94                 assert item != null;
     95                 offset = AlignmentUtils.alignOffset(offset, ItemType.ItemAlignment);
     96                 offset = item.placeAt(offset, i);
     97             }
     98         } else {
     99             this.offset = 0;
    100         }
    101 
    102         return offset;
    103     }
    104 
    105     /**
    106      * Write the items to the given <code>AnnotatedOutput</code>
    107      * @param out the <code>AnnotatedOutput</code> object to write to
    108      */
    109     protected void writeTo(AnnotatedOutput out) {
    110         out.annotate(0, " ");
    111         out.annotate(0, "-----------------------------");
    112         out.annotate(0, this.ItemType.TypeName + " section");
    113         out.annotate(0, "-----------------------------");
    114         out.annotate(0, " ");
    115 
    116         for (Item item: items) {
    117             assert item!=null;
    118             out.alignTo(ItemType.ItemAlignment);
    119             item.writeTo(out);
    120             out.annotate(0, " ");
    121         }
    122     }
    123 
    124     /**
    125      * Read the specified number of items from the given <code>Input</code> object
    126      * @param size The number of items to read
    127      * @param in The <code>Input</code> object to read from
    128      * @param readContext a <code>ReadContext</code> object to hold information that is
    129      * only needed while reading in a file
    130      */
    131     protected void readFrom(int size, Input in, ReadContext readContext) {
    132         //readItems() expects that the list will already be the correct size, so add null items
    133         //until we reach the specified size
    134         items.ensureCapacity(size);
    135         for (int i = items.size(); i < size; i++) {
    136             items.add(null);
    137         }
    138 
    139         in.alignTo(ItemType.ItemAlignment);
    140         offset = in.getCursor();
    141 
    142         //call the subclass's method that actually reads in the items
    143         readItems(in, readContext);
    144     }
    145 
    146     /**
    147      * This method in the concrete item subclass should read in all the items from the given <code>Input</code>
    148      * object, using any pre-created items as applicable (i.e. items that were created prior to reading in the
    149      * section, by other items requesting items from this section that they reference by index/offset)
    150      * @param in the <code>Input</code>
    151      * @param readContext a <code>ReadContext</code> object to hold information that is
    152      * only needed while reading in a file
    153      */
    154     protected abstract void readItems(Input in, ReadContext readContext);
    155 
    156     /**
    157      * Gets the offset where the first item in this section is placed
    158      * @return the ofset where the first item in this section is placed
    159      */
    160     public int getOffset() {
    161         return offset;
    162     }
    163 
    164     /**
    165      * Gets a the items contained in this section as a read-only list
    166      * @return A read-only <code>List</code> object containing the items in this section
    167      */
    168     public List<T> getItems() {
    169         return Collections.unmodifiableList(items);
    170     }
    171 
    172     /**
    173      * This method checks if an item that is equivalent to the given item has already been added. If found,
    174      * it returns that item. If not found, it adds the given item to this section and returns it.
    175      * @param item the item to intern
    176      * @return An item from this section that is equivalent to the given item. It may or may not be the same
    177      * as the item passed to this method.
    178      */
    179     protected T intern(T item) {
    180         if (item == null) {
    181             return null;
    182         }
    183         T internedItem = getInternedItem(item);
    184         if (internedItem == null) {
    185             uniqueItems.put(item, item);
    186             items.add(item);
    187             return item;
    188         }
    189         return internedItem;
    190     }
    191 
    192     /**
    193      * Returns the interned item that is equivalent to the given item, or null
    194      * @param item the item to check
    195      * @return the interned item that is equivalent to the given item, or null
    196      */
    197     protected T getInternedItem(T item) {
    198         if (uniqueItems == null) {
    199             buildInternedItemMap();
    200         }
    201         return uniqueItems.get(item);
    202     }
    203 
    204     /**
    205      * Builds the interned item map from the items that are in this section
    206      */
    207     private void buildInternedItemMap() {
    208         uniqueItems = new HashMap<T,T>();
    209         for (T item: items) {
    210             assert item != null;
    211             uniqueItems.put(item, item);
    212         }
    213     }
    214 
    215     /**
    216      * Sorts the items in the section
    217      */
    218     protected void sortSection() {
    219         Collections.sort(items);
    220     }
    221 }