1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/* 2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project 3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License. 6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at 7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and 14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License. 15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpackage com.android.dx.dex.file; 18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 19fe107fb6e3f308ac5174ebdc5a794ee880c741d9Jesse Wilsonimport com.android.dex.util.ExceptionWithContext; 20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.AnnotatedOutput; 21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport com.android.dx.util.Hex; 22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.ArrayList; 23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Arrays; 24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Collection; 25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Collections; 26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Comparator; 27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.HashMap; 28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.Map; 29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.NoSuchElementException; 30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.TreeMap; 31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/** 3399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * A section of a {@code .dex} file which consists of a sequence of 34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * {@link OffsettedItem} objects, which may each be of a different concrete 35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * class and/or size. 36de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro * 37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <b>Note:</b> It is invalid for an item in an instance of this class to 38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * have a larger alignment requirement than the alignment of this instance. 39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic final class MixedItemSection extends Section { 41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project static enum SortType { 42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** no sorting */ 43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project NONE, 44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** sort by type only */ 46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project TYPE, 47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** sort in class-major order, with instances sorted per-class */ 49f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project INSTANCE; 50f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project }; 51f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 5299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project /** {@code non-null;} sorter which sorts instances by type */ 53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private static final Comparator<OffsettedItem> TYPE_SORTER = 54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project new Comparator<OffsettedItem>() { 55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public int compare(OffsettedItem item1, OffsettedItem item2) { 56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ItemType type1 = item1.itemType(); 57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project ItemType type2 = item2.itemType(); 58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return type1.compareTo(type2); 59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project }; 61de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro 6299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project /** {@code non-null;} the items in this part */ 63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private final ArrayList<OffsettedItem> items; 64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 6599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project /** {@code non-null;} items that have been explicitly interned */ 66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private final HashMap<OffsettedItem, OffsettedItem> interns; 67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 6899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project /** {@code non-null;} how to sort the items */ 69f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private final SortType sort; 70f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 7299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * {@code >= -1;} the current size of this part, in bytes, or {@code -1} 73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * if not yet calculated 74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project private int writeSize; 76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Constructs an instance. The file offset is initially unknown. 79de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro * 8099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * @param name {@code null-ok;} the name of this instance, for annotation 81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * purposes 8299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * @param file {@code non-null;} file that this instance is part of 8399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * @param alignment {@code > 0;} alignment requirement for the final output; 84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * must be a power of 2 85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @param sort how the items should be sorted in the final output 86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 87f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public MixedItemSection(String name, DexFile file, int alignment, 88f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project SortType sort) { 89f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project super(name, file, alignment); 90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.items = new ArrayList<OffsettedItem>(100); 92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.interns = new HashMap<OffsettedItem, OffsettedItem>(100); 93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.sort = sort; 94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project this.writeSize = -1; 95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** {@inheritDoc} */ 98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project @Override 99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public Collection<? extends Item> items() { 100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return items; 101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** {@inheritDoc} */ 104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project @Override 105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public int writeSize() { 106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throwIfNotPrepared(); 107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return writeSize; 108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** {@inheritDoc} */ 111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project @Override 112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public int getAbsoluteItemOffset(Item item) { 113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project OffsettedItem oi = (OffsettedItem) item; 114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return oi.getAbsoluteOffset(); 115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Gets the size of this instance, in items. 119de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro * 12099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * @return {@code >= 0;} the size 121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public int size() { 123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return items.size(); 124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Writes the portion of the file header that refers to this instance. 128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * 12999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * @param out {@code non-null;} where to write 130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public void writeHeaderPart(AnnotatedOutput out) { 132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throwIfNotPrepared(); 133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (writeSize == -1) { 135de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro throw new RuntimeException("write size not yet set"); 136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int sz = writeSize; 139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int offset = (sz == 0) ? 0 : getFileOffset(); 140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project String name = getName(); 141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (name == null) { 143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project name = "<unnamed>"; 144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int spaceCount = 15 - name.length(); 147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project char[] spaceArr = new char[spaceCount]; 148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Arrays.fill(spaceArr, ' '); 149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project String spaces = new String(spaceArr); 150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (out.annotates()) { 152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project out.annotate(4, name + "_size:" + spaces + Hex.u4(sz)); 153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project out.annotate(4, name + "_off: " + spaces + Hex.u4(offset)); 154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project out.writeInt(sz); 157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project out.writeInt(offset); 158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Adds an item to this instance. This will in turn tell the given item 162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * that it has been added to this instance. It is invalid to add the 163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * same item to more than one instance, nor to add the same items 164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * multiple times to a single instance. 165de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro * 16699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * @param item {@code non-null;} the item to add 167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public void add(OffsettedItem item) { 169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throwIfPrepared(); 170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project try { 172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (item.getAlignment() > getAlignment()) { 173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throw new IllegalArgumentException( 174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "incompatible item alignment"); 175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } catch (NullPointerException ex) { 177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project // Elucidate the exception. 178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throw new NullPointerException("item == null"); 179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project items.add(item); 182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Interns an item in this instance, returning the interned instance 186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * (which may not be the one passed in). This will add the item if no 187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * equal item has been added. 188de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro * 18999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * @param item {@code non-null;} the item to intern 19099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * @return {@code non-null;} the equivalent interned instance 191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public <T extends OffsettedItem> T intern(T item) { 193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throwIfPrepared(); 194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project OffsettedItem result = interns.get(item); 196de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro 197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (result != null) { 198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return (T) result; 199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project add(item); 202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project interns.put(item, item); 203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return item; 204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Gets an item which was previously interned. 208de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro * 20999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * @param item {@code non-null;} the item to look for 21099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * @return {@code non-null;} the equivalent already-interned instance 211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public <T extends OffsettedItem> T get(T item) { 213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throwIfNotPrepared(); 214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project OffsettedItem result = interns.get(item); 216de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro 217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (result != null) { 218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return (T) result; 219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throw new NoSuchElementException(item.toString()); 222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Writes an index of contents of the items in this instance of the 226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * given type. If there are none, this writes nothing. If there are any, 227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * then the index is preceded by the given intro string. 228de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro * 22999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * @param out {@code non-null;} where to write to 23099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * @param itemType {@code non-null;} the item type of interest 23199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * @param intro {@code non-null;} the introductory string for non-empty indices 232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public void writeIndexAnnotation(AnnotatedOutput out, ItemType itemType, 234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project String intro) { 235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throwIfNotPrepared(); 236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project TreeMap<String, OffsettedItem> index = 238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project new TreeMap<String, OffsettedItem>(); 239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (OffsettedItem item : items) { 241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (item.itemType() == itemType) { 242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project String label = item.toHuman(); 243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project index.put(label, item); 244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (index.size() == 0) { 248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project return; 249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project out.annotate(0, intro); 252de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro 253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (Map.Entry<String, OffsettedItem> entry : index.entrySet()) { 254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project String label = entry.getKey(); 255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project OffsettedItem item = entry.getValue(); 256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project out.annotate(0, item.offsetString() + ' ' + label + '\n'); 257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** {@inheritDoc} */ 261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project @Override 262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project protected void prepare0() { 263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project DexFile file = getFile(); 264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /* 266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * It's okay for new items to be added as a result of an 267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * addContents() call; we just have to deal with the possibility. 268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int i = 0; 271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (;;) { 272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int sz = items.size(); 273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (i >= sz) { 274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project break; 275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (/*i*/; i < sz; i++) { 278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project OffsettedItem one = items.get(i); 279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project one.addContents(file); 280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** 285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Places all the items in this instance at particular offsets. This 286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * will call {@link OffsettedItem#place} on each item. If an item 28799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * does not know its write size before the call to {@code place}, 288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * it is that call which is responsible for setting the write size. 289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This method may only be called once per instance; subsequent calls 290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * will throw an exception. 291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */ 292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project public void placeItems() { 293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throwIfNotPrepared(); 294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project switch (sort) { 296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project case INSTANCE: { 297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Collections.sort(items); 298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project break; 299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project case TYPE: { 301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project Collections.sort(items, TYPE_SORTER); 302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project break; 303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int sz = items.size(); 307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int outAt = 0; 308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (int i = 0; i < sz; i++) { 309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project OffsettedItem one = items.get(i); 310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project try { 311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int placedAt = one.place(this, outAt); 312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (placedAt < outAt) { 314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throw new RuntimeException("bogus place() result for " + 315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project one); 316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project outAt = placedAt + one.writeSize(); 319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } catch (RuntimeException ex) { 320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throw ExceptionWithContext.withContext(ex, 321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project "...while placing " + one); 322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project writeSize = outAt; 326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project /** {@inheritDoc} */ 329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project @Override 330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project protected void writeTo0(AnnotatedOutput out) { 331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project boolean annotates = out.annotates(); 332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project boolean first = true; 333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project DexFile file = getFile(); 334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int at = 0; 335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project for (OffsettedItem one : items) { 337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (annotates) { 338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (first) { 339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project first = false; 340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } else { 341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project out.annotate(0, "\n"); 342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int alignMask = one.getAlignment() - 1; 346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project int writeAt = (at + alignMask) & ~alignMask; 347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (at != writeAt) { 349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project out.writeZeroes(writeAt - at); 350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project at = writeAt; 351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project one.writeTo(file, out); 354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project at += one.writeSize(); 355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project 357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project if (at != writeSize) { 358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project throw new RuntimeException("output size mismatch"); 359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project } 361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} 362