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