1579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/* 2579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Copyright (C) 2007 The Android Open Source Project 3579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 4579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Licensed under the Apache License, Version 2.0 (the "License"); 5579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * you may not use this file except in compliance with the License. 6579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * You may obtain a copy of the License at 7579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 8579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * http://www.apache.org/licenses/LICENSE-2.0 9579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 10579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Unless required by applicable law or agreed to in writing, software 11579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS, 12579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * See the License for the specific language governing permissions and 14579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * limitations under the License. 15579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 16579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 17579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpackage com.android.dx.dex.file; 18579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 19579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.AnnotatedOutput; 20579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport com.android.dx.util.Hex; 21579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 22579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.HashMap; 23579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonimport java.util.List; 24579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 25579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson/** 26579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Class that represents a contiguous list of uniform items. Each 27579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * item in the list, in particular, must have the same write size and 28579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * alignment. 29579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 30579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * <p>This class inherits its alignment from its items, bumped up to 31579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * {@code 4} if the items have a looser alignment requirement. If 32579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * it is more than {@code 4}, then there will be a gap after the 33579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * output list size (which is four bytes) and before the first item.</p> 34579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 35579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param <T> type of element contained in an instance 36579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 37579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilsonpublic final class UniformListItem<T extends OffsettedItem> 38579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson extends OffsettedItem { 39579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** the size of the list header */ 40579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private static final int HEADER_SIZE = 4; 41579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 42579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** {@code non-null;} the item type */ 43579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private final ItemType itemType; 44579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 45579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** {@code non-null;} the contents */ 46579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private final List<T> items; 47579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 48579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** 49579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Constructs an instance. It is illegal to modify the given list once 50579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * it is used to construct an instance of this class. 51579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 52579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param itemType {@code non-null;} the type of the item 53579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param items {@code non-null and non-empty;} list of items to represent 54579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 55579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public UniformListItem(ItemType itemType, List<T> items) { 56579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson super(getAlignment(items), writeSize(items)); 57579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 58579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (itemType == null) { 59579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new NullPointerException("itemType == null"); 60579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 61579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 62579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson this.items = items; 63579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson this.itemType = itemType; 64579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 65579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 66579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** 67579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Helper for {@link #UniformListItem}, which returns the alignment 68579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * requirement implied by the given list. See the header comment for 69579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * more details. 70579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 71579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param items {@code non-null;} list of items being represented 72579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @return {@code >= 4;} the alignment requirement 73579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 74579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private static int getAlignment(List<? extends OffsettedItem> items) { 75579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson try { 76579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson // Since they all must have the same alignment, any one will do. 77579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return Math.max(HEADER_SIZE, items.get(0).getAlignment()); 78579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } catch (IndexOutOfBoundsException ex) { 79579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson // Translate the exception. 80579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new IllegalArgumentException("items.size() == 0"); 81579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } catch (NullPointerException ex) { 82579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson // Translate the exception. 83579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new NullPointerException("items == null"); 84579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 85579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 86579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 87579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** 88579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Calculates the write size for the given list. 89579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 90579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @param items {@code non-null;} the list in question 91579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @return {@code >= 0;} the write size 92579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 93579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private static int writeSize(List<? extends OffsettedItem> items) { 94579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /* 95579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * This class assumes all included items are the same size, 96579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * an assumption which is verified in place0(). 97579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 98579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson OffsettedItem first = items.get(0); 99579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return (items.size() * first.writeSize()) + getAlignment(items); 100579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 101579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 102579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** {@inheritDoc} */ 103579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson @Override 104579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public ItemType itemType() { 105579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return itemType; 106579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 107579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 108579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** {@inheritDoc} */ 109579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson @Override 110579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public String toString() { 111579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson StringBuffer sb = new StringBuffer(100); 112579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 113579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson sb.append(getClass().getName()); 114579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson sb.append(items); 115579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 116579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return sb.toString(); 117579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 118579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 119579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** {@inheritDoc} */ 120579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson @Override 121579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public void addContents(DexFile file) { 122579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson for (OffsettedItem i : items) { 123579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson i.addContents(file); 124579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 125579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 126579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 127579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** {@inheritDoc} */ 128579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson @Override 129579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public final String toHuman() { 130579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson StringBuffer sb = new StringBuffer(100); 131579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson boolean first = true; 132579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 133579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson sb.append("{"); 134579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 135579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson for (OffsettedItem i : items) { 136579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (first) { 137579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson first = false; 138579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } else { 139579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson sb.append(", "); 140579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 141579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson sb.append(i.toHuman()); 142579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 143579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 144579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson sb.append("}"); 145579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return sb.toString(); 146579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 147579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 148579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** 149579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Gets the underlying list of items. 150579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 151579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @return {@code non-null;} the list 152579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 153579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson public final List<T> getItems() { 154579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return items; 155579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 156579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 157579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** {@inheritDoc} */ 158579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson @Override 159579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson protected void place0(Section addedTo, int offset) { 160579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson offset += headerSize(); 161579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 162579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson boolean first = true; 163579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int theSize = -1; 164579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int theAlignment = -1; 165579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 166579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson for (OffsettedItem i : items) { 167579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int size = i.writeSize(); 168579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (first) { 169579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson theSize = size; 170579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson theAlignment = i.getAlignment(); 171579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson first = false; 172579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } else { 173579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (size != theSize) { 174579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new UnsupportedOperationException( 175579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson "item size mismatch"); 176579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 177579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (i.getAlignment() != theAlignment) { 178579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson throw new UnsupportedOperationException( 179579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson "item alignment mismatch"); 180579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 181579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 182579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 183579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson offset = i.place(addedTo, offset) + size; 184579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 185579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 186579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 187579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** {@inheritDoc} */ 188579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson @Override 189579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson protected void writeTo0(DexFile file, AnnotatedOutput out) { 190579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson int size = items.size(); 191579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 192579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson if (out.annotates()) { 193579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson out.annotate(0, offsetString() + " " + typeName()); 194579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson out.annotate(4, " size: " + Hex.u4(size)); 195579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 196579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 197579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson out.writeInt(size); 198579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 199579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson for (OffsettedItem i : items) { 200579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson i.writeTo(file, out); 201579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 202579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 203579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson 204579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /** 205579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Get the size of the header of this list. 206579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * 207579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * @return {@code >= 0;} the header size 208579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 209579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson private int headerSize() { 210579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson /* 211579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * Because of how this instance was set up, this is the same 212579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson * as the alignment. 213579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson */ 214579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson return getAlignment(); 215579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson } 216579d7739c53a2707ad711a2d2cae46d7d782f06Jesse Wilson} 217