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