AnnotationsDirectory.java revision 84c1762a62d7fc6638432c6c56e0422aa8cc6939
1/* 2 * Copyright 2012, Google Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32package org.jf.dexlib2.dexbacked.util; 33 34import com.google.common.collect.ImmutableList; 35import com.google.common.collect.ImmutableSet; 36import org.jf.dexlib2.dexbacked.DexBackedAnnotation; 37import org.jf.dexlib2.dexbacked.DexBackedDexFile; 38 39import javax.annotation.Nonnull; 40import java.util.List; 41import java.util.Set; 42 43public abstract class AnnotationsDirectory { 44 public static final AnnotationsDirectory EMPTY = new AnnotationsDirectory() { 45 @Override public int getFieldAnnotationCount() { return 0; } 46 @Nonnull @Override public Set<? extends DexBackedAnnotation> getClassAnnotations() { return ImmutableSet.of(); } 47 @Nonnull @Override public AnnotationIterator getFieldAnnotationIterator() { return AnnotationIterator.EMPTY; } 48 @Nonnull @Override public AnnotationIterator getMethodAnnotationIterator() { return AnnotationIterator.EMPTY; } 49 @Nonnull @Override public AnnotationIterator getParameterAnnotationIterator() {return AnnotationIterator.EMPTY;} 50 }; 51 52 public abstract int getFieldAnnotationCount(); 53 @Nonnull public abstract Set<? extends DexBackedAnnotation> getClassAnnotations(); 54 @Nonnull public abstract AnnotationIterator getFieldAnnotationIterator(); 55 @Nonnull public abstract AnnotationIterator getMethodAnnotationIterator(); 56 @Nonnull public abstract AnnotationIterator getParameterAnnotationIterator(); 57 58 @Nonnull 59 public static AnnotationsDirectory newOrEmpty(@Nonnull DexBackedDexFile dexFile, 60 int directoryAnnotationsOffset) { 61 if (directoryAnnotationsOffset == 0) { 62 return EMPTY; 63 } 64 return new AnnotationsDirectoryImpl(dexFile, directoryAnnotationsOffset); 65 } 66 67 68 public interface AnnotationIterator { 69 public static final AnnotationIterator EMPTY = new AnnotationIterator() { 70 @Override public int seekTo(int fieldIndex) { return 0; } 71 public void reset() {} 72 }; 73 74 public int seekTo(int fieldIndex); 75 public void reset(); 76 } 77 78 @Nonnull 79 public static Set<? extends DexBackedAnnotation> getAnnotations(@Nonnull final DexBackedDexFile dexFile, 80 final int annotationSetOffset) { 81 if (annotationSetOffset != 0) { 82 final int size = dexFile.readSmallUint(annotationSetOffset); 83 return new FixedSizeSet<DexBackedAnnotation>() { 84 @Nonnull 85 @Override 86 public DexBackedAnnotation readItem(int index) { 87 int annotationOffset = dexFile.readSmallUint(annotationSetOffset + 4 + (4*index)); 88 return new DexBackedAnnotation(dexFile, annotationOffset); 89 } 90 91 @Override public int size() { return size; } 92 }; 93 } 94 95 return ImmutableSet.of(); 96 } 97 98 @Nonnull 99 public static List<Set<? extends DexBackedAnnotation>> getParameterAnnotations( 100 @Nonnull final DexBackedDexFile dexFile, final int annotationSetListOffset) { 101 if (annotationSetListOffset > 0) { 102 final int size = dexFile.readSmallUint(annotationSetListOffset); 103 104 return new FixedSizeList<Set<? extends DexBackedAnnotation>>() { 105 @Nonnull 106 @Override 107 public Set<? extends DexBackedAnnotation> readItem(int index) { 108 int annotationSetOffset = dexFile.readSmallUint(annotationSetListOffset + 4 + index * 4); 109 return getAnnotations(dexFile, annotationSetOffset); 110 } 111 112 @Override public int size() { return size; } 113 }; 114 } 115 return ImmutableList.of(); 116 } 117 118 private static class AnnotationsDirectoryImpl extends AnnotationsDirectory { 119 @Nonnull public final DexBackedDexFile dexFile; 120 private final int directoryOffset; 121 122 private static final int FIELD_COUNT_OFFSET = 4; 123 private static final int METHOD_COUNT_OFFSET = 8; 124 private static final int PARAMETER_COUNT_OFFSET = 12; 125 private static final int ANNOTATIONS_START_OFFSET = 16; 126 127 /** The size of a field_annotation structure */ 128 private static final int FIELD_ANNOTATION_SIZE = 8; 129 /** The size of a method_annotation structure */ 130 private static final int METHOD_ANNOTATION_SIZE = 8; 131 132 public AnnotationsDirectoryImpl(@Nonnull DexBackedDexFile dexFile, 133 int directoryOffset) { 134 this.dexFile = dexFile; 135 this.directoryOffset = directoryOffset; 136 } 137 138 public int getFieldAnnotationCount() { 139 return dexFile.readSmallUint(directoryOffset + FIELD_COUNT_OFFSET); 140 } 141 142 public int getMethodAnnotationCount() { 143 return dexFile.readSmallUint(directoryOffset + METHOD_COUNT_OFFSET); 144 } 145 146 public int getParameterAnnotationCount() { 147 return dexFile.readSmallUint(directoryOffset + PARAMETER_COUNT_OFFSET); 148 } 149 150 @Nonnull 151 public Set<? extends DexBackedAnnotation> getClassAnnotations() { 152 return getAnnotations(dexFile, dexFile.readSmallUint(directoryOffset)); 153 } 154 155 @Nonnull 156 public AnnotationIterator getFieldAnnotationIterator() { 157 int fieldAnnotationCount = getFieldAnnotationCount(); 158 if (fieldAnnotationCount == 0) { 159 return AnnotationIterator.EMPTY; 160 } 161 return new AnnotationIteratorImpl(directoryOffset + ANNOTATIONS_START_OFFSET, fieldAnnotationCount); 162 } 163 164 @Nonnull 165 public AnnotationIterator getMethodAnnotationIterator() { 166 int methodCount = getMethodAnnotationCount(); 167 if (methodCount == 0) { 168 return AnnotationIterator.EMPTY; 169 } 170 int fieldCount = getFieldAnnotationCount(); 171 int methodAnnotationsOffset = directoryOffset + ANNOTATIONS_START_OFFSET + 172 fieldCount * FIELD_ANNOTATION_SIZE; 173 return new AnnotationIteratorImpl(methodAnnotationsOffset, methodCount); 174 } 175 176 @Nonnull 177 public AnnotationIterator getParameterAnnotationIterator() { 178 int parameterAnnotationCount = getParameterAnnotationCount(); 179 if (parameterAnnotationCount == 0) { 180 return AnnotationIterator.EMPTY; 181 } 182 int fieldCount = getFieldAnnotationCount(); 183 int methodCount = getMethodAnnotationCount(); 184 int parameterAnnotationsOffset = directoryOffset + ANNOTATIONS_START_OFFSET + 185 fieldCount * FIELD_ANNOTATION_SIZE + 186 methodCount * METHOD_ANNOTATION_SIZE; 187 return new AnnotationIteratorImpl(parameterAnnotationsOffset, parameterAnnotationCount); 188 } 189 190 private class AnnotationIteratorImpl implements AnnotationIterator { 191 private final int startOffset; 192 private final int size; 193 private int currentIndex; 194 private int currentItemIndex; 195 196 public AnnotationIteratorImpl(int startOffset, int size) { 197 this.startOffset = startOffset; 198 this.size = size; 199 this.currentItemIndex = dexFile.readSmallUint(startOffset); 200 this.currentIndex = 0; 201 } 202 203 public int seekTo(int itemIndex) { 204 while (currentItemIndex < itemIndex && (currentIndex+1) < size) { 205 currentIndex++; 206 currentItemIndex = dexFile.readSmallUint(startOffset + (currentIndex*8)); 207 } 208 209 if (currentItemIndex == itemIndex) { 210 return dexFile.readSmallUint(startOffset + (currentIndex*8)+4); 211 } 212 return 0; 213 } 214 215 public void reset() { 216 this.currentItemIndex = dexFile.readSmallUint(startOffset); 217 this.currentIndex = 0; 218 } 219 } 220 } 221} 222