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.ExceptionWithContext;
     32 import org.jf.dexlib.Util.SparseArray;
     33 
     34 import java.util.List;
     35 
     36 
     37 /**
     38  * This class stores context information that is only needed when reading in a dex file
     39  * Namely, it handles "pre-creating" items when an item needs to resolve some other item
     40  * that it references, and keeps track of those pre-created items, so the corresponding section
     41  * for the pre-created items uses them, instead of creating new items
     42  */
     43 public class ReadContext {
     44     private SparseArray<TypeListItem> typeListItems = new SparseArray<TypeListItem>(0);
     45     private SparseArray<AnnotationSetRefList> annotationSetRefLists = new SparseArray<AnnotationSetRefList>(0);
     46     private SparseArray<AnnotationSetItem> annotationSetItems = new SparseArray<AnnotationSetItem>(0);
     47     private SparseArray<ClassDataItem> classDataItems = new SparseArray<ClassDataItem>(0);
     48     private SparseArray<CodeItem> codeItems = new SparseArray<CodeItem>(0);
     49     private SparseArray<StringDataItem> stringDataItems = new SparseArray<StringDataItem>(0);
     50     private SparseArray<DebugInfoItem> debugInfoItems = new SparseArray<DebugInfoItem>(0);
     51     private SparseArray<AnnotationItem> annotationItems = new SparseArray<AnnotationItem>(0);
     52     private SparseArray<EncodedArrayItem> encodedArrayItems = new SparseArray<EncodedArrayItem>(0);
     53     private SparseArray<AnnotationDirectoryItem> annotationDirectoryItems = new SparseArray<AnnotationDirectoryItem>(0);
     54 
     55     private SparseArray[] itemsByType = new SparseArray[] {
     56             null, //string_id_item
     57             null, //type_id_item
     58             null, //proto_id_item
     59             null, //field_id_item
     60             null, //method_id_item
     61             null, //class_def_item
     62             typeListItems,
     63             annotationSetRefLists,
     64             annotationSetItems,
     65             classDataItems,
     66             codeItems,
     67             stringDataItems,
     68             debugInfoItems,
     69             annotationItems,
     70             encodedArrayItems,
     71             annotationDirectoryItems,
     72             null, //map_list
     73             null //header_item
     74     };
     75 
     76 
     77     /**
     78      * The section sizes that are passed in while reading HeaderItem/MapItem, via the
     79      * addSection method.
     80      */
     81     private int[] sectionSizes = new int[18];
     82 
     83     /**
     84      * The section offsets that are passed in while reading MapItem/HeaderItem, via the
     85      * addSection method.
     86      */
     87     private int[] sectionOffsets = new int[18];
     88 
     89     /**
     90      * Creates a new ReadContext instance.
     91      */
     92     public ReadContext() {
     93         for (int i=0; i<18; i++) {
     94             sectionSizes[i] = -1;
     95             sectionOffsets[i] = -1;
     96         }
     97     }
     98 
     99     /**
    100      * Gets the offsetted item of the specified type for the given offset. This method does not support retrieving an
    101      * optional item where a value of 0 indicates "not present". Use getOptionalOffsettedItemByOffset instead.
    102      *
    103      * @param itemType The type of item to get
    104      * @param offset The offset of the item
    105      * @return the offsetted item of the specified type at the specified offset
    106      */
    107     public Item getOffsettedItemByOffset(ItemType itemType, int offset) {
    108         assert !itemType.isIndexedItem();
    109 
    110         SparseArray<Item> sa = itemsByType[itemType.SectionIndex];
    111         Item item = sa.get(offset);
    112         if (item == null) {
    113             throw new ExceptionWithContext(String.format("Could not find the %s item at offset %#x",
    114                     itemType.TypeName, offset));
    115         }
    116         return item;
    117     }
    118 
    119     /**
    120      * Gets the optional offsetted item of the specified type for the given offset
    121      *
    122      * @param itemType The type of item to get
    123      * @param offset The offset of the item
    124      * @return the offsetted item of the specified type at the specified offset, or null if the offset is 0
    125      */
    126     public Item getOptionalOffsettedItemByOffset(ItemType itemType, int offset) {
    127         assert !itemType.isIndexedItem();
    128 
    129         assert !itemType.isIndexedItem();
    130 
    131         SparseArray<Item> sa = itemsByType[itemType.SectionIndex];
    132         Item item = sa.get(offset);
    133         if (item == null && offset != 0) {
    134             throw new ExceptionWithContext(String.format("Could not find the %s item at offset %#x",
    135                     itemType.TypeName, offset));
    136         }
    137         return item;
    138     }
    139 
    140     /**
    141      * Adds the size and offset information for the given offset
    142      * @param itemType the item type of the section
    143      * @param sectionSize the size of the section
    144      * @param sectionOffset the offset of the section
    145      */
    146     public void addSection(final ItemType itemType, int sectionSize, int sectionOffset) {
    147         int storedSectionSize = sectionSizes[itemType.SectionIndex];
    148         if (storedSectionSize == -1) {
    149             sectionSizes[itemType.SectionIndex] = sectionSize;
    150         } else {
    151             if (storedSectionSize  != sectionSize) {
    152                 throw new RuntimeException("The section size in the header and map for item type "
    153                         + itemType + " do not match");
    154             }
    155         }
    156 
    157         int storedSectionOffset = sectionOffsets[itemType.SectionIndex];
    158         if (storedSectionOffset == -1) {
    159             sectionOffsets[itemType.SectionIndex] = sectionOffset;
    160         } else {
    161             if (storedSectionOffset != sectionOffset) {
    162                 throw new RuntimeException("The section offset in the header and map for item type "
    163                         + itemType + " do not match");
    164             }
    165         }
    166     }
    167 
    168     /**
    169      * Sets the items for the specified section. This should be called by an offsetted section
    170      * after it is finished reading in all its items.
    171      * @param itemType the item type of the section. This must be an offsetted item type
    172      * @param items the full list of items in the section, ordered by offset
    173      */
    174     public void setItemsForSection(ItemType itemType, List<? extends Item> items) {
    175         assert !itemType.isIndexedItem();
    176 
    177         SparseArray<Item> sa = itemsByType[itemType.SectionIndex];
    178 
    179         sa.ensureCapacity(items.size());
    180         for (Item item: items) {
    181             sa.append(item.getOffset(), item);
    182         }
    183     }
    184 
    185     /**
    186      * @param itemType the item type of the section
    187      * @return the size of the given section as it was read in from the map item
    188      */
    189     public int getSectionSize(ItemType itemType) {
    190         return sectionSizes[itemType.SectionIndex];
    191     }
    192 
    193     /**
    194      * @param itemType the item type of the section
    195      * @return the offset of the given section as it was read in from the map item
    196      */
    197     public int getSectionOffset(ItemType itemType) {
    198         return sectionOffsets[itemType.SectionIndex];
    199     }
    200 }
    201