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.Hex;
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectimport java.util.List;
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/**
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Class that represents a contiguous list of uniform items. Each
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * item in the list, in particular, must have the same write size and
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * alignment.
27de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro *
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * <p>This class inherits its alignment from its items, bumped up to
2999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * {@code 4} if the items have a looser alignment requirement. If
3099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * it is more than {@code 4}, then there will be a gap after the
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * output list size (which is four bytes) and before the first item.</p>
32de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro *
33f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * @param <T> type of element contained in an instance
34f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
35f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectpublic final class UniformListItem<T extends OffsettedItem>
36f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        extends OffsettedItem {
37f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** the size of the list header */
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static final int HEADER_SIZE = 4;
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
4099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} the item type */
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final ItemType itemType;
42de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
4399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /** {@code non-null;} the contents */
44f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private final List<T> items;
45f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
46f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
47f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Constructs an instance. It is illegal to modify the given list once
48f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * it is used to construct an instance of this class.
49de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
5099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param itemType {@code non-null;} the type of the item
5199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param items {@code non-null and non-empty;} list of items to represent
52f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
53f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public UniformListItem(ItemType itemType, List<T> items) {
54f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        super(getAlignment(items), writeSize(items));
55f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
56f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (itemType == null) {
57f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("itemType == null");
58f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
59f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
60f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.items = items;
61f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        this.itemType = itemType;
62f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
63f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
64f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
65f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Helper for {@link #UniformListItem}, which returns the alignment
66f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * requirement implied by the given list. See the header comment for
67f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * more details.
68de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
6999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param items {@code non-null;} list of items being represented
7099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 4;} the alignment requirement
71f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
72f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static int getAlignment(List<? extends OffsettedItem> items) {
73f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        try {
74f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // Since they all must have the same alignment, any one will do.
75f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return Math.max(HEADER_SIZE, items.get(0).getAlignment());
76f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (IndexOutOfBoundsException ex) {
77f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // Translate the exception.
78f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new IllegalArgumentException("items.size() == 0");
79f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } catch (NullPointerException ex) {
80f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            // Translate the exception.
81f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            throw new NullPointerException("items == null");
82de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro        }
83f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
84f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
85f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
86f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Calculates the write size for the given list.
87de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
8899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @param items {@code non-null;} the list in question
8999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 0;} the write size
90f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
91f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private static int writeSize(List<? extends OffsettedItem> items) {
92f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
93f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * This class assumes all included items are the same size,
94f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * an assumption which is verified in place0().
95f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
96f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        OffsettedItem first = items.get(0);
97f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return (items.size() * first.writeSize()) + getAlignment(items);
98f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
99f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public ItemType itemType() {
103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return itemType;
104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public String toString() {
109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        StringBuffer sb = new StringBuffer(100);
110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sb.append(getClass().getName());
112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sb.append(items);
113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return sb.toString();
115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public void addContents(DexFile file) {
120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (OffsettedItem i : items) {
121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            i.addContents(file);
122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public final String toHuman() {
128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        StringBuffer sb = new StringBuffer(100);
129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean first = true;
130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sb.append("{");
132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (OffsettedItem i : items) {
134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (first) {
135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                first = false;
136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                sb.append(", ");
138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            sb.append(i.toHuman());
140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        sb.append("}");
143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return sb.toString();
144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Gets the underlying list of items.
148de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
14999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code non-null;} the list
150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    public final List<T> getItems() {
152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return items;
153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    protected void place0(Section addedTo, int offset) {
158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        offset += headerSize();
159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        boolean first = true;
161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int theSize = -1;
162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int theAlignment = -1;
163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (OffsettedItem i : items) {
165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int size = i.writeSize();
166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (first) {
167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                theSize = size;
168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                theAlignment = i.getAlignment();
169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                first = false;
170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (size != theSize) {
172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw new UnsupportedOperationException(
173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            "item size mismatch");
174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (i.getAlignment() != theAlignment) {
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    throw new UnsupportedOperationException(
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                            "item alignment mismatch");
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                }
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
180de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            offset = i.place(addedTo, offset) + size;
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /** {@inheritDoc} */
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    @Override
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    protected void writeTo0(DexFile file, AnnotatedOutput out) {
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int size = items.size();
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (out.annotates()) {
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            out.annotate(0, offsetString() + " " + typeName());
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            out.annotate(4, "  size: " + Hex.u4(size));
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        out.writeInt(size);
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (OffsettedItem i : items) {
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            i.writeTo(file, out);
199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /**
203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Get the size of the header of this list.
204de75089fb7216d19e9c22cce4dc62a49513477d3Carl Shapiro     *
20599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * @return {@code >= 0;} the header size
206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    private int headerSize() {
208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Because of how this instance was set up, this is the same
210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * as the alignment.
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return getAlignment();
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
215