1/* 2 * Copyright (C) 2008 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.dx.dex.file; 18 19import com.android.dx.rop.annotation.Annotation; 20import com.android.dx.rop.annotation.Annotations; 21import com.android.dx.util.AnnotatedOutput; 22import com.android.dx.util.Hex; 23 24/** 25 * Set of annotations, where no annotation type appears more than once. 26 */ 27public final class AnnotationSetItem extends OffsettedItem { 28 /** the required alignment for instances of this class */ 29 private static final int ALIGNMENT = 4; 30 31 /** the size of an entry int the set: one {@code uint} */ 32 private static final int ENTRY_WRITE_SIZE = 4; 33 34 /** {@code non-null;} the set of annotations */ 35 private final Annotations annotations; 36 37 /** 38 * {@code non-null;} set of annotations as individual items in an array. 39 * <b>Note:</b> The contents have to get sorted by type id before 40 * writing. 41 */ 42 private final AnnotationItem[] items; 43 44 /** 45 * Constructs an instance. 46 * 47 * @param annotations {@code non-null;} set of annotations 48 * @param dexFile {@code non-null;} dex output 49 */ 50 public AnnotationSetItem(Annotations annotations, DexFile dexFile) { 51 super(ALIGNMENT, writeSize(annotations)); 52 53 this.annotations = annotations; 54 this.items = new AnnotationItem[annotations.size()]; 55 56 int at = 0; 57 for (Annotation a : annotations.getAnnotations()) { 58 items[at] = new AnnotationItem(a, dexFile); 59 at++; 60 } 61 } 62 63 /** 64 * Gets the write size for the given set. 65 * 66 * @param annotations {@code non-null;} the set 67 * @return {@code > 0;} the write size 68 */ 69 private static int writeSize(Annotations annotations) { 70 // This includes an int size at the start of the list. 71 72 try { 73 return (annotations.size() * ENTRY_WRITE_SIZE) + 4; 74 } catch (NullPointerException ex) { 75 // Elucidate the exception. 76 throw new NullPointerException("list == null"); 77 } 78 } 79 80 /** 81 * Gets the underlying annotations of this instance 82 * 83 * @return {@code non-null;} the annotations 84 */ 85 public Annotations getAnnotations() { 86 return annotations; 87 } 88 89 /** {@inheritDoc} */ 90 @Override 91 public int hashCode() { 92 return annotations.hashCode(); 93 } 94 95 /** {@inheritDoc} */ 96 @Override 97 protected int compareTo0(OffsettedItem other) { 98 AnnotationSetItem otherSet = (AnnotationSetItem) other; 99 100 return annotations.compareTo(otherSet.annotations); 101 } 102 103 /** {@inheritDoc} */ 104 @Override 105 public ItemType itemType() { 106 return ItemType.TYPE_ANNOTATION_SET_ITEM; 107 } 108 109 /** {@inheritDoc} */ 110 @Override 111 public String toHuman() { 112 return annotations.toString(); 113 } 114 115 /** {@inheritDoc} */ 116 @Override 117 public void addContents(DexFile file) { 118 MixedItemSection byteData = file.getByteData(); 119 int size = items.length; 120 121 for (int i = 0; i < size; i++) { 122 items[i] = byteData.intern(items[i]); 123 } 124 } 125 126 /** {@inheritDoc} */ 127 @Override 128 protected void place0(Section addedTo, int offset) { 129 // Sort the array to be in type id index order. 130 AnnotationItem.sortByTypeIdIndex(items); 131 } 132 133 /** {@inheritDoc} */ 134 @Override 135 protected void writeTo0(DexFile file, AnnotatedOutput out) { 136 boolean annotates = out.annotates(); 137 int size = items.length; 138 139 if (annotates) { 140 out.annotate(0, offsetString() + " annotation set"); 141 out.annotate(4, " size: " + Hex.u4(size)); 142 } 143 144 out.writeInt(size); 145 146 for (int i = 0; i < size; i++) { 147 AnnotationItem item = items[i]; 148 int offset = item.getAbsoluteOffset(); 149 150 if (annotates) { 151 out.annotate(4, " entries[" + Integer.toHexString(i) + "]: " + 152 Hex.u4(offset)); 153 items[i].annotateTo(out, " "); 154 } 155 156 out.writeInt(offset); 157 } 158 } 159} 160