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 17package com.android.dexgen.dex.file; 18 19import com.android.dexgen.rop.cst.Constant; 20import com.android.dexgen.rop.cst.CstType; 21import com.android.dexgen.rop.type.Type; 22import com.android.dexgen.util.AnnotatedOutput; 23import com.android.dexgen.util.Hex; 24 25import java.util.Collection; 26import java.util.TreeMap; 27 28/** 29 * Type identifiers list section of a {@code .dex} file. 30 */ 31public final class TypeIdsSection extends UniformItemSection { 32 /** 33 * {@code non-null;} map from types to {@link TypeIdItem} instances 34 */ 35 private final TreeMap<Type, TypeIdItem> typeIds; 36 37 /** 38 * Constructs an instance. The file offset is initially unknown. 39 * 40 * @param file {@code non-null;} file that this instance is part of 41 */ 42 public TypeIdsSection(DexFile file) { 43 super("type_ids", file, 4); 44 45 typeIds = new TreeMap<Type, TypeIdItem>(); 46 } 47 48 /** {@inheritDoc} */ 49 @Override 50 public Collection<? extends Item> items() { 51 return typeIds.values(); 52 } 53 54 /** {@inheritDoc} */ 55 @Override 56 public IndexedItem get(Constant cst) { 57 if (cst == null) { 58 throw new NullPointerException("cst == null"); 59 } 60 61 throwIfNotPrepared(); 62 63 Type type = ((CstType) cst).getClassType(); 64 IndexedItem result = typeIds.get(type); 65 66 if (result == null) { 67 throw new IllegalArgumentException("not found: " + cst); 68 } 69 70 return result; 71 } 72 73 /** 74 * Writes the portion of the file header that refers to this instance. 75 * 76 * @param out {@code non-null;} where to write 77 */ 78 public void writeHeaderPart(AnnotatedOutput out) { 79 throwIfNotPrepared(); 80 81 int sz = typeIds.size(); 82 int offset = (sz == 0) ? 0 : getFileOffset(); 83 84 if (sz > 65536) { 85 throw new UnsupportedOperationException("too many type ids"); 86 } 87 88 if (out.annotates()) { 89 out.annotate(4, "type_ids_size: " + Hex.u4(sz)); 90 out.annotate(4, "type_ids_off: " + Hex.u4(offset)); 91 } 92 93 out.writeInt(sz); 94 out.writeInt(offset); 95 } 96 97 /** 98 * Interns an element into this instance. 99 * 100 * @param type {@code non-null;} the type to intern 101 * @return {@code non-null;} the interned reference 102 */ 103 public TypeIdItem intern(Type type) { 104 if (type == null) { 105 throw new NullPointerException("type == null"); 106 } 107 108 throwIfPrepared(); 109 110 TypeIdItem result = typeIds.get(type); 111 112 if (result == null) { 113 result = new TypeIdItem(new CstType(type)); 114 typeIds.put(type, result); 115 } 116 117 return result; 118 } 119 120 /** 121 * Interns an element into this instance. 122 * 123 * @param type {@code non-null;} the type to intern 124 * @return {@code non-null;} the interned reference 125 */ 126 public TypeIdItem intern(CstType type) { 127 if (type == null) { 128 throw new NullPointerException("type == null"); 129 } 130 131 throwIfPrepared(); 132 133 Type typePerSe = type.getClassType(); 134 TypeIdItem result = typeIds.get(typePerSe); 135 136 if (result == null) { 137 result = new TypeIdItem(type); 138 typeIds.put(typePerSe, result); 139 } 140 141 return result; 142 } 143 144 /** 145 * Gets the index of the given type, which must have 146 * been added to this instance. 147 * 148 * @param type {@code non-null;} the type to look up 149 * @return {@code >= 0;} the reference's index 150 */ 151 public int indexOf(Type type) { 152 if (type == null) { 153 throw new NullPointerException("type == null"); 154 } 155 156 throwIfNotPrepared(); 157 158 TypeIdItem item = typeIds.get(type); 159 160 if (item == null) { 161 throw new IllegalArgumentException("not found: " + type); 162 } 163 164 return item.getIndex(); 165 } 166 167 /** 168 * Gets the index of the given type, which must have 169 * been added to this instance. 170 * 171 * @param type {@code non-null;} the type to look up 172 * @return {@code >= 0;} the reference's index 173 */ 174 public int indexOf(CstType type) { 175 if (type == null) { 176 throw new NullPointerException("type == null"); 177 } 178 179 return indexOf(type.getClassType()); 180 } 181 182 /** {@inheritDoc} */ 183 @Override 184 protected void orderItems() { 185 int idx = 0; 186 187 for (Object i : items()) { 188 ((TypeIdItem) i).setIndex(idx); 189 idx++; 190 } 191 } 192} 193