AnnotationsDirectory.java revision 779bf9bccba5e27317e9b50a059fa1bae73decbb
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 org.jf.dexlib2.dexbacked.DexFile; 36import org.jf.dexlib2.dexbacked.DexBackedAnnotation; 37 38import javax.annotation.Nonnull; 39import java.util.List; 40 41public abstract class AnnotationsDirectory { 42 public static final AnnotationsDirectory EMPTY = new AnnotationsDirectory() { 43 @Override public int getFieldAnnotationCount() { return 0; } 44 @Nonnull @Override public List<? extends DexBackedAnnotation> getClassAnnotations() {return ImmutableList.of();} 45 @Nonnull @Override public AnnotationIterator getFieldAnnotationIterator() { return AnnotationIterator.EMPTY; } 46 @Nonnull @Override public AnnotationIterator getMethodAnnotationIterator() { return AnnotationIterator.EMPTY; } 47 @Nonnull @Override public AnnotationIterator getParameterAnnotationIterator() {return AnnotationIterator.EMPTY;} 48 }; 49 50 public abstract int getFieldAnnotationCount(); 51 @Nonnull public abstract List<? extends DexBackedAnnotation> getClassAnnotations(); 52 @Nonnull public abstract AnnotationIterator getFieldAnnotationIterator(); 53 @Nonnull public abstract AnnotationIterator getMethodAnnotationIterator(); 54 @Nonnull public abstract AnnotationIterator getParameterAnnotationIterator(); 55 56 public static AnnotationsDirectory newOrEmpty(@Nonnull DexFile dexFile, 57 int directoryAnnotationsOffset) { 58 if (directoryAnnotationsOffset == 0) { 59 return EMPTY; 60 } 61 return new AnnotationsDirectoryImpl(dexFile, directoryAnnotationsOffset); 62 } 63 64 65 public interface AnnotationIterator { 66 public static final AnnotationIterator EMPTY = new AnnotationIterator() { 67 @Override public int seekTo(int fieldIndex) { return 0; } 68 }; 69 70 public int seekTo(int fieldIndex); 71 } 72 73 @Nonnull 74 public static List<? extends DexBackedAnnotation> getAnnotations(@Nonnull final DexFile dexFile, 75 final int annotationSetOffset) { 76 if (annotationSetOffset != 0) { 77 final int size = dexFile.readSmallUint(annotationSetOffset); 78 return new FixedSizeList<DexBackedAnnotation>() { 79 @Override 80 public DexBackedAnnotation readItem(int index) { 81 int annotationOffset = dexFile.readSmallUint(annotationSetOffset + 4 + (4*index)); 82 return new DexBackedAnnotation(dexFile, annotationOffset); 83 } 84 85 @Override public int size() { return size; } 86 }; 87 } 88 89 return ImmutableList.of(); 90 } 91 92 public static List<List<? extends DexBackedAnnotation>> getParameterAnnotations(@Nonnull final DexFile dexFile, 93 final int annotationSetListOffset) { 94 if (annotationSetListOffset > 0) { 95 final int size = dexFile.readSmallUint(annotationSetListOffset); 96 97 return new FixedSizeList<List<? extends DexBackedAnnotation>>() { 98 @Override 99 public List<? extends DexBackedAnnotation> readItem(int index) { 100 int annotationSetOffset = dexFile.readSmallUint(annotationSetListOffset + 4 + index * 4); 101 return getAnnotations(dexFile, annotationSetOffset); 102 } 103 104 @Override public int size() { return size; } 105 }; 106 } 107 return ImmutableList.of(); 108 } 109 110 private static class AnnotationsDirectoryImpl extends AnnotationsDirectory { 111 @Nonnull public final DexFile dexFile; 112 private final int directoryOffset; 113 114 private static final int FIELD_COUNT_OFFSET = 4; 115 private static final int METHOD_COUNT_OFFSET = 8; 116 private static final int PARAMETER_COUNT_OFFSET = 12; 117 private static final int ANNOTATIONS_START_OFFSET = 16; 118 119 /** The size of a field_annotation structure */ 120 private static final int FIELD_ANNOTATION_SIZE = 8; 121 /** The size of a method_annotation structure */ 122 private static final int METHOD_ANNOTATION_SIZE = 8; 123 124 public AnnotationsDirectoryImpl(@Nonnull DexFile dexFile, 125 int directoryOffset) { 126 this.dexFile = dexFile; 127 this.directoryOffset = directoryOffset; 128 } 129 130 public int getFieldAnnotationCount() { 131 return dexFile.readSmallUint(directoryOffset + FIELD_COUNT_OFFSET); 132 } 133 134 public int getMethodAnnotationCount() { 135 return dexFile.readSmallUint(directoryOffset + METHOD_COUNT_OFFSET); 136 } 137 138 public int getParameterAnnotationCount() { 139 return dexFile.readSmallUint(directoryOffset + PARAMETER_COUNT_OFFSET); 140 } 141 142 @Nonnull 143 public List<? extends DexBackedAnnotation> getClassAnnotations() { 144 return getAnnotations(dexFile, dexFile.readSmallUint(directoryOffset)); 145 } 146 147 @Nonnull 148 public AnnotationIterator getFieldAnnotationIterator() { 149 return new AnnotationIteratorImpl(directoryOffset + ANNOTATIONS_START_OFFSET, getFieldAnnotationCount()); 150 } 151 152 @Nonnull 153 public AnnotationIterator getMethodAnnotationIterator() { 154 int fieldCount = getFieldAnnotationCount(); 155 int methodAnnotationsOffset = directoryOffset + ANNOTATIONS_START_OFFSET + 156 fieldCount * FIELD_ANNOTATION_SIZE; 157 return new AnnotationIteratorImpl(methodAnnotationsOffset, getMethodAnnotationCount()); 158 } 159 160 @Nonnull 161 public AnnotationIterator getParameterAnnotationIterator() { 162 int fieldCount = getFieldAnnotationCount(); 163 int methodCount = getMethodAnnotationCount(); 164 int parameterAnnotationsOffset = directoryOffset + ANNOTATIONS_START_OFFSET + 165 fieldCount * FIELD_ANNOTATION_SIZE + 166 methodCount + METHOD_ANNOTATION_SIZE; 167 return new AnnotationIteratorImpl(parameterAnnotationsOffset, getParameterAnnotationCount()); 168 } 169 170 private class AnnotationIteratorImpl implements AnnotationIterator { 171 private final int startOffset; 172 private final int size; 173 private int currentIndex; 174 private int currentItemIndex; 175 176 public AnnotationIteratorImpl(int startOffset, int size) { 177 this.startOffset = startOffset; 178 this.size = size; 179 if (size > 0) { 180 currentItemIndex = dexFile.readSmallUint(startOffset); 181 this.currentIndex = 0; 182 } else { 183 currentItemIndex = -1; 184 this.currentIndex = -1; 185 } 186 } 187 188 public int seekTo(int itemIndex) { 189 while (currentItemIndex < itemIndex && (currentIndex+1) < size) { 190 currentIndex++; 191 currentItemIndex = dexFile.readSmallUint(startOffset + (currentIndex*8)); 192 } 193 194 if (currentItemIndex == itemIndex) { 195 return dexFile.readSmallUint(startOffset + (currentIndex*8)+4); 196 } 197 return 0; 198 } 199 } 200 } 201} 202