• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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      */
Section(DexFile dexFile, ItemType itemType)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      */
placeAt(int offset)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      */
writeTo(AnnotatedOutput out)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      */
readFrom(int size, Input in, ReadContext readContext)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      */
readItems(Input in, ReadContext readContext)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      */
getOffset()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      */
getItems()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      */
intern(T item)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      */
getInternedItem(T item)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      */
buildInternedItemMap()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      */
sortSection()218     protected void sortSection() {
219         Collections.sort(items);
220     }
221 }