1917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/* 2917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Copyright (C) 2007 The Android Open Source Project 3917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 4917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Licensed under the Apache License, Version 2.0 (the "License"); 5917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * you may not use this file except in compliance with the License. 6917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * You may obtain a copy of the License at 7917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 8917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * http://www.apache.org/licenses/LICENSE-2.0 9917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 10917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Unless required by applicable law or agreed to in writing, software 11917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * distributed under the License is distributed on an "AS IS" BASIS, 12917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * See the License for the specific language governing permissions and 14917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * limitations under the License. 15917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 16917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 17917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpackage com.android.dexgen.dex.file; 18917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 19917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.AnnotatedOutput; 20917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.ExceptionWithContext; 21917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport com.android.dexgen.util.Hex; 22917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 23917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.ArrayList; 24917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.Arrays; 25917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.Collection; 26917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.Collections; 27917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.Comparator; 28917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.HashMap; 29917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.Map; 30917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.NoSuchElementException; 31917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulimport java.util.TreeMap; 32917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 33917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul/** 34917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * A section of a {@code .dex} file which consists of a sequence of 35917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * {@link OffsettedItem} objects, which may each be of a different concrete 36917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * class and/or size. 37917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 38917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * <b>Note:</b> It is invalid for an item in an instance of this class to 39917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * have a larger alignment requirement than the alignment of this instance. 40917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 41917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgulpublic final class MixedItemSection extends Section { 42917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul static enum SortType { 43917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** no sorting */ 44917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul NONE, 45917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 46917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** sort by type only */ 47917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul TYPE, 48917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 49917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** sort in class-major order, with instances sorted per-class */ 50917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul INSTANCE; 51917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul }; 52917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 53917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** {@code non-null;} sorter which sorts instances by type */ 54917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private static final Comparator<OffsettedItem> TYPE_SORTER = 55917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul new Comparator<OffsettedItem>() { 56917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public int compare(OffsettedItem item1, OffsettedItem item2) { 57917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul ItemType type1 = item1.itemType(); 58917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul ItemType type2 = item2.itemType(); 59917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return type1.compareTo(type2); 60917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 61917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul }; 62917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 63917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** {@code non-null;} the items in this part */ 64917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private final ArrayList<OffsettedItem> items; 65917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 66917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** {@code non-null;} items that have been explicitly interned */ 67917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private final HashMap<OffsettedItem, OffsettedItem> interns; 68917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 69917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** {@code non-null;} how to sort the items */ 70917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private final SortType sort; 71917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 72917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 73917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * {@code >= -1;} the current size of this part, in bytes, or {@code -1} 74917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * if not yet calculated 75917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 76917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul private int writeSize; 77917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 78917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 79917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Constructs an instance. The file offset is initially unknown. 80917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 81917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param name {@code null-ok;} the name of this instance, for annotation 82917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * purposes 83917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param file {@code non-null;} file that this instance is part of 84917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param alignment {@code > 0;} alignment requirement for the final output; 85917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * must be a power of 2 86917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param sort how the items should be sorted in the final output 87917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 88917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public MixedItemSection(String name, DexFile file, int alignment, 89917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul SortType sort) { 90917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul super(name, file, alignment); 91917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 92917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul this.items = new ArrayList<OffsettedItem>(100); 93917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul this.interns = new HashMap<OffsettedItem, OffsettedItem>(100); 94917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul this.sort = sort; 95917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul this.writeSize = -1; 96917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 97917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 98917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** {@inheritDoc} */ 99917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul @Override 100917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public Collection<? extends Item> items() { 101917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return items; 102917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 103917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 104917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** {@inheritDoc} */ 105917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul @Override 106917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public int writeSize() { 107917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throwIfNotPrepared(); 108917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return writeSize; 109917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 110917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 111917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** {@inheritDoc} */ 112917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul @Override 113917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public int getAbsoluteItemOffset(Item item) { 114917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul OffsettedItem oi = (OffsettedItem) item; 115917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return oi.getAbsoluteOffset(); 116917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 117917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 118917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 119917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Gets the size of this instance, in items. 120917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 121917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @return {@code >= 0;} the size 122917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 123917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public int size() { 124917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return items.size(); 125917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 126917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 127917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 128917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Writes the portion of the file header that refers to this instance. 129917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 130917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param out {@code non-null;} where to write 131917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 132917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public void writeHeaderPart(AnnotatedOutput out) { 133917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throwIfNotPrepared(); 134917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 135917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (writeSize == -1) { 136917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throw new RuntimeException("write size not yet set"); 137917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 138917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 139917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int sz = writeSize; 140917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int offset = (sz == 0) ? 0 : getFileOffset(); 141917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul String name = getName(); 142917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 143917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (name == null) { 144917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul name = "<unnamed>"; 145917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 146917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 147917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int spaceCount = 15 - name.length(); 148917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul char[] spaceArr = new char[spaceCount]; 149917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul Arrays.fill(spaceArr, ' '); 150917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul String spaces = new String(spaceArr); 151917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 152917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (out.annotates()) { 153917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul out.annotate(4, name + "_size:" + spaces + Hex.u4(sz)); 154917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul out.annotate(4, name + "_off: " + spaces + Hex.u4(offset)); 155917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 156917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 157917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul out.writeInt(sz); 158917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul out.writeInt(offset); 159917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 160917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 161917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 162917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Adds an item to this instance. This will in turn tell the given item 163917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * that it has been added to this instance. It is invalid to add the 164917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * same item to more than one instance, nor to add the same items 165917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * multiple times to a single instance. 166917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 167917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param item {@code non-null;} the item to add 168917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 169917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public void add(OffsettedItem item) { 170917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throwIfPrepared(); 171917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 172917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul try { 173917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (item.getAlignment() > getAlignment()) { 174917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throw new IllegalArgumentException( 175917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul "incompatible item alignment"); 176917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 177917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } catch (NullPointerException ex) { 178917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul // Elucidate the exception. 179917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throw new NullPointerException("item == null"); 180917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 181917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 182917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul items.add(item); 183917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 184917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 185917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 186917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Interns an item in this instance, returning the interned instance 187917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * (which may not be the one passed in). This will add the item if no 188917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * equal item has been added. 189917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 190917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param item {@code non-null;} the item to intern 191917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @return {@code non-null;} the equivalent interned instance 192917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 193917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public <T extends OffsettedItem> T intern(T item) { 194917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throwIfPrepared(); 195917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 196917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul OffsettedItem result = interns.get(item); 197917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 198917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (result != null) { 199917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return (T) result; 200917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 201917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 202917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul add(item); 203917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul interns.put(item, item); 204917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return item; 205917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 206917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 207917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 208917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Gets an item which was previously interned. 209917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 210917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param item {@code non-null;} the item to look for 211917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @return {@code non-null;} the equivalent already-interned instance 212917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 213917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public <T extends OffsettedItem> T get(T item) { 214917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throwIfNotPrepared(); 215917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 216917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul OffsettedItem result = interns.get(item); 217917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 218917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (result != null) { 219917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return (T) result; 220917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 221917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 222917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throw new NoSuchElementException(item.toString()); 223917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 224917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 225917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 226917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Writes an index of contents of the items in this instance of the 227917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * given type. If there are none, this writes nothing. If there are any, 228917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * then the index is preceded by the given intro string. 229917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * 230917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param out {@code non-null;} where to write to 231917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param itemType {@code non-null;} the item type of interest 232917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * @param intro {@code non-null;} the introductory string for non-empty indices 233917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 234917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public void writeIndexAnnotation(AnnotatedOutput out, ItemType itemType, 235917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul String intro) { 236917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throwIfNotPrepared(); 237917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 238917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul TreeMap<String, OffsettedItem> index = 239917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul new TreeMap<String, OffsettedItem>(); 240917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 241917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (OffsettedItem item : items) { 242917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (item.itemType() == itemType) { 243917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul String label = item.toHuman(); 244917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul index.put(label, item); 245917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 246917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 247917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 248917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (index.size() == 0) { 249917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul return; 250917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 251917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 252917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul out.annotate(0, intro); 253917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 254917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (Map.Entry<String, OffsettedItem> entry : index.entrySet()) { 255917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul String label = entry.getKey(); 256917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul OffsettedItem item = entry.getValue(); 257917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul out.annotate(0, item.offsetString() + ' ' + label + '\n'); 258917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 259917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 260917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 261917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** {@inheritDoc} */ 262917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul @Override 263917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul protected void prepare0() { 264917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul DexFile file = getFile(); 265917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 266917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /* 267917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * It's okay for new items to be added as a result of an 268917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * addContents() call; we just have to deal with the possibility. 269917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 270917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 271917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int i = 0; 272917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (;;) { 273917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int sz = items.size(); 274917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (i >= sz) { 275917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul break; 276917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 277917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 278917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (/*i*/; i < sz; i++) { 279917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul OffsettedItem one = items.get(i); 280917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul one.addContents(file); 281917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 282917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 283917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 284917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 285917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** 286917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * Places all the items in this instance at particular offsets. This 287917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * will call {@link OffsettedItem#place} on each item. If an item 288917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * does not know its write size before the call to {@code place}, 289917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * it is that call which is responsible for setting the write size. 290917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * This method may only be called once per instance; subsequent calls 291917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul * will throw an exception. 292917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul */ 293917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul public void placeItems() { 294917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throwIfNotPrepared(); 295917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 296917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul switch (sort) { 297917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul case INSTANCE: { 298917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul Collections.sort(items); 299917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul break; 300917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 301917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul case TYPE: { 302917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul Collections.sort(items, TYPE_SORTER); 303917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul break; 304917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 305917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 306917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 307917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int sz = items.size(); 308917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int outAt = 0; 309917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (int i = 0; i < sz; i++) { 310917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul OffsettedItem one = items.get(i); 311917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul try { 312917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int placedAt = one.place(this, outAt); 313917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 314917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (placedAt < outAt) { 315917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throw new RuntimeException("bogus place() result for " + 316917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul one); 317917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 318917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 319917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul outAt = placedAt + one.writeSize(); 320917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } catch (RuntimeException ex) { 321917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throw ExceptionWithContext.withContext(ex, 322917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul "...while placing " + one); 323917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 324917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 325917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 326917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul writeSize = outAt; 327917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 328917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 329917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul /** {@inheritDoc} */ 330917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul @Override 331917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul protected void writeTo0(AnnotatedOutput out) { 332917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul boolean annotates = out.annotates(); 333917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul boolean first = true; 334917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul DexFile file = getFile(); 335917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int at = 0; 336917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 337917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul for (OffsettedItem one : items) { 338917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (annotates) { 339917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (first) { 340917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul first = false; 341917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } else { 342917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul out.annotate(0, "\n"); 343917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 344917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 345917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 346917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int alignMask = one.getAlignment() - 1; 347917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul int writeAt = (at + alignMask) & ~alignMask; 348917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 349917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (at != writeAt) { 350917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul out.writeZeroes(writeAt - at); 351917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul at = writeAt; 352917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 353917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 354917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul one.writeTo(file, out); 355917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul at += one.writeSize(); 356917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 357917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul 358917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul if (at != writeSize) { 359917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul throw new RuntimeException("output size mismatch"); 360917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 361917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul } 362917cb222329ee8c035c3ffaf947e4265761b9367Piotr Gurgul} 363