1 /* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.dx.dex.file; 18 19 import com.android.dex.DexException; 20 import com.android.dex.DexFormat; 21 import com.android.dex.DexIndexOverflowException; 22 import com.android.dx.command.dexer.Main; 23 import com.android.dx.rop.cst.Constant; 24 import com.android.dx.rop.cst.CstType; 25 import com.android.dx.rop.type.Type; 26 import com.android.dx.util.AnnotatedOutput; 27 import com.android.dx.util.Hex; 28 29 import java.util.Collection; 30 import java.util.TreeMap; 31 32 /** 33 * Type identifiers list section of a {@code .dex} file. 34 */ 35 public final class TypeIdsSection extends UniformItemSection { 36 /** 37 * {@code non-null;} map from types to {@link TypeIdItem} instances 38 */ 39 private final TreeMap<Type, TypeIdItem> typeIds; 40 41 /** 42 * Constructs an instance. The file offset is initially unknown. 43 * 44 * @param file {@code non-null;} file that this instance is part of 45 */ 46 public TypeIdsSection(DexFile file) { 47 super("type_ids", file, 4); 48 49 typeIds = new TreeMap<Type, TypeIdItem>(); 50 } 51 52 /** {@inheritDoc} */ 53 @Override 54 public Collection<? extends Item> items() { 55 return typeIds.values(); 56 } 57 58 /** {@inheritDoc} */ 59 @Override 60 public IndexedItem get(Constant cst) { 61 if (cst == null) { 62 throw new NullPointerException("cst == null"); 63 } 64 65 throwIfNotPrepared(); 66 67 Type type = ((CstType) cst).getClassType(); 68 IndexedItem result = typeIds.get(type); 69 70 if (result == null) { 71 throw new IllegalArgumentException("not found: " + cst); 72 } 73 74 return result; 75 } 76 77 /** 78 * Writes the portion of the file header that refers to this instance. 79 * 80 * @param out {@code non-null;} where to write 81 */ 82 public void writeHeaderPart(AnnotatedOutput out) { 83 throwIfNotPrepared(); 84 85 int sz = typeIds.size(); 86 int offset = (sz == 0) ? 0 : getFileOffset(); 87 88 if (sz > DexFormat.MAX_TYPE_IDX + 1) { 89 throw new DexIndexOverflowException("Too many type references: " + sz + 90 "; max is " + (DexFormat.MAX_TYPE_IDX + 1) + ".\n" + 91 Main.getTooManyIdsErrorMessage()); 92 } 93 94 if (out.annotates()) { 95 out.annotate(4, "type_ids_size: " + Hex.u4(sz)); 96 out.annotate(4, "type_ids_off: " + Hex.u4(offset)); 97 } 98 99 out.writeInt(sz); 100 out.writeInt(offset); 101 } 102 103 /** 104 * Interns an element into this instance. 105 * 106 * @param type {@code non-null;} the type to intern 107 * @return {@code non-null;} the interned reference 108 */ 109 public synchronized TypeIdItem intern(Type type) { 110 if (type == null) { 111 throw new NullPointerException("type == null"); 112 } 113 114 throwIfPrepared(); 115 116 TypeIdItem result = typeIds.get(type); 117 118 if (result == null) { 119 result = new TypeIdItem(new CstType(type)); 120 typeIds.put(type, result); 121 } 122 123 return result; 124 } 125 126 /** 127 * Interns an element into this instance. 128 * 129 * @param type {@code non-null;} the type to intern 130 * @return {@code non-null;} the interned reference 131 */ 132 public synchronized TypeIdItem intern(CstType type) { 133 if (type == null) { 134 throw new NullPointerException("type == null"); 135 } 136 137 throwIfPrepared(); 138 139 Type typePerSe = type.getClassType(); 140 TypeIdItem result = typeIds.get(typePerSe); 141 142 if (result == null) { 143 result = new TypeIdItem(type); 144 typeIds.put(typePerSe, result); 145 } 146 147 return result; 148 } 149 150 /** 151 * Gets the index of the given type, which must have 152 * been added to this instance. 153 * 154 * @param type {@code non-null;} the type to look up 155 * @return {@code >= 0;} the reference's index 156 */ 157 public int indexOf(Type type) { 158 if (type == null) { 159 throw new NullPointerException("type == null"); 160 } 161 162 throwIfNotPrepared(); 163 164 TypeIdItem item = typeIds.get(type); 165 166 if (item == null) { 167 throw new IllegalArgumentException("not found: " + type); 168 } 169 170 return item.getIndex(); 171 } 172 173 /** 174 * Gets the index of the given type, which must have 175 * been added to this instance. 176 * 177 * @param type {@code non-null;} the type to look up 178 * @return {@code >= 0;} the reference's index 179 */ 180 public int indexOf(CstType type) { 181 if (type == null) { 182 throw new NullPointerException("type == null"); 183 } 184 185 return indexOf(type.getClassType()); 186 } 187 188 /** {@inheritDoc} */ 189 @Override 190 protected void orderItems() { 191 int idx = 0; 192 193 for (Object i : items()) { 194 ((TypeIdItem) i).setIndex(idx); 195 idx++; 196 } 197 } 198 } 199