Mercurial > hg > icedrobot > daneel
changeset 54:3e27a236f4b7
Added parser for annotation directories.
Reviewed-by: Remi Forax
* dex/AnnotationsDirectory.java: New parser class.
* dex/ClassData.java: Factored out encoded_array decoding.
* dex/ClassDef.java: Call new parser class for annotations.
* dex/EncodedValue.java (parseArray, parseAnnotation): New decoder methods.
* (AnnotationValue): New internal model class for encoded annotations.
author | Michael Starzinger <michi@complang.tuwien.ac.at> |
---|---|
date | Sun, 20 Mar 2011 19:31:39 +0100 |
parents | e6fa81ffbda9 |
children | 80952fd2bbd4 |
files | src/main/java/org/icedrobot/daneel/dex/AnnotationsDirectory.java src/main/java/org/icedrobot/daneel/dex/ClassData.java src/main/java/org/icedrobot/daneel/dex/ClassDef.java src/main/java/org/icedrobot/daneel/dex/EncodedValue.java |
diffstat | 4 files changed, 275 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/org/icedrobot/daneel/dex/AnnotationsDirectory.java Sun Mar 20 19:31:39 2011 +0100 @@ -0,0 +1,193 @@ +/* + * Daneel - Dalvik to Java bytecode compiler + * Copyright (C) 2011 IcedRobot team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * This file is subject to the "Classpath" exception: + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give you + * permission to link this library with independent modules to produce an + * executable, regardless of the license terms of these independent + * modules, and to copy and distribute the resulting executable under terms + * of your choice, provided that you also meet, for each linked independent + * module, the terms and conditions of the license of that module. An + * independent module is a module which is not derived from or based on + * this library. If you modify this library, you may extend this exception + * to your version of the library, but you are not obligated to do so. If + * you do not wish to do so, delete this exception statement from your + * version. + */ + +package org.icedrobot.daneel.dex; + +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; + +import org.icedrobot.daneel.dex.EncodedValue.AnnotationValue; + +/** + * A parser class capable of parsing {@code annotations_directory_item} + * structures as part of DEX files. Keep package-private to hide internal API. + */ +class AnnotationsDirectory { + + /** + * Parses a {@code annotations_directory_item} structure in a DEX file at + * the buffer's current position. + * + * @param buffer The byte buffer to read from. + * @param dex The DEX file currently being parsed. + * @return An object representing the parsed data. + */ + public static AnnotationsDirectory parse(ByteBuffer buffer, DexFile dex) { + return new AnnotationsDirectory(buffer, dex); + } + + private final Annotation[] classAnnotations; + + private final Map<Integer, Annotation[]> fieldAnnotations; + + private final Map<Integer, Annotation[]> methodAnnotations; + + private final Map<Integer, Annotation[][]> parameterAnnotations; + + private AnnotationsDirectory(ByteBuffer buffer, DexFile dex) { + int classAnnotationsOff = buffer.getInt(); + int fieldsSize = buffer.getInt(); + int methodsSize = buffer.getInt(); + int parametersSize = buffer.getInt(); + + // Parse annotation_set_item structure for class annotations. + if (classAnnotationsOff != 0) { + ByteBuffer buf = dex.getDataBuffer(classAnnotationsOff); + classAnnotations = parseAnnotations(buf, dex); + } else + classAnnotations = null; + + // Parse annotation_set_item structures in field_annotations array. + fieldAnnotations = new HashMap<Integer, Annotation[]>(fieldsSize); + for (int i = 0; i < fieldsSize; i++) { + int fieldIdx = buffer.getInt(); + int annotationsOff = buffer.getInt(); + ByteBuffer buf = dex.getDataBuffer(annotationsOff); + Annotation[] annotations = parseAnnotations(buf, dex); + fieldAnnotations.put(fieldIdx, annotations); + } + + // Parse annotation_set_item structures in method_annotations array. + methodAnnotations = new HashMap<Integer, Annotation[]>(methodsSize); + for (int i = 0; i < methodsSize; i++) { + int methodIdx = buffer.getInt(); + int annotationsOff = buffer.getInt(); + ByteBuffer buf = dex.getDataBuffer(annotationsOff); + Annotation[] annotations = parseAnnotations(buf, dex); + methodAnnotations.put(methodIdx, annotations); + } + + // Parse annotation_set_ref_list and contained annotation_set_item + // structures in parameter_annotations array. + parameterAnnotations = new HashMap<Integer, Annotation[][]>(); + for (int i = 0; i < parametersSize; i++) { + /*int methodIdx = buffer.getInt(); + int annotationsOff = buffer.getInt(); + ByteBuffer buf = dex.getDataBuffer(annotationsOff); + int size = buf.getInt(); + int[] list = BufferUtil.getInts(buf, size); + Annotation[][] annotationSet = new Annotation[size][]; + for (int j = 0; j < size; j++) { + buf = dex.getDataBuffer(list[j]); + annotationSet[j] = parseAnnotations(buf, dex); + } + parameterAnnotations.put(methodIdx, annotationSet);*/ + throw new UnsupportedOperationException("Not yet tested!"); + } + } + + /** + * Returns all class annotations present in this directory or {@code null} + * if there are no such annotations. + * + * @return An array containing the annotation items or {@code null}. + */ + public Annotation[] getClassAnnotations() { + return classAnnotations; + } + + /** + * Returns all field annotations for the given field index present in this + * directory or {@code null} if there are no such annotations. + * + * @param idx The given field index. + * @return An array containing the annotation items or {@code null}. + */ + public Annotation[] getFieldAnnotations(int idx) { + return fieldAnnotations.get(idx); + } + + /** + * Returns all method annotations for the given method index present in this + * directory or {@code null} if there are no such annotations. + * + * @param idx The given field index. + * @return An array containing the annotation items or {@code null}. + */ + public Annotation[] getMethodAnnotations(int idx) { + return methodAnnotations.get(idx); + } + + /** + * Helper method decoding an {@code annotation_set_item} array. + * + * @param buffer The byte buffer to read from. + * @param dex The DEX file currently being parsed. + * @return An array containing all the encoded annotation items. + */ + private static Annotation[] parseAnnotations(ByteBuffer buffer, DexFile dex) { + int size = buffer.getInt(); + Annotation[] annotations = new Annotation[size]; + for (int i = 0; i < size; i++) { + int annotationOff = buffer.getInt(); + ByteBuffer buf = dex.getDataBuffer(annotationOff); + annotations[i] = new Annotation(buf, dex); + } + return annotations; + } + + /** + * An internal representation of an annotation as encoded in the {@code + * annotation_item} structure. + */ + static class Annotation { + public static final int VISIBILITY_BUILD = 0x00; + public static final int VISIBILITY_RUNTIME = 0x01; + public static final int VISIBILITY_SYSTEM = 0x02; + + protected final int visibility; + protected final AnnotationValue annotationValue; + + public Annotation(ByteBuffer buffer, DexFile dex) { + visibility = buffer.get(); + annotationValue = EncodedValue.parseAnnotation(buffer, dex); + System.out.printf("ANNOTATION: vis=0x%02x, val=%s\n", visibility, + annotationValue); + } + }; +}
--- a/src/main/java/org/icedrobot/daneel/dex/ClassData.java Sat Mar 19 23:37:56 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/ClassData.java Sun Mar 20 19:31:39 2011 +0100 @@ -148,10 +148,7 @@ // Parse encoded_array_item and contained encoded_value structures. if (staticValuesOff != 0) { ByteBuffer buf = dex.getDataBuffer(staticValuesOff); - int staticValuesSize = BufferUtil.getULEB128(buf); - staticValues = new Object[staticValuesSize]; - for (int i = 0; i < staticValuesSize; i++) - staticValues[i] = EncodedValue.parse(buf, dex); + staticValues = EncodedValue.parseArray(buf, dex); } else staticValues = new Object[0]; }
--- a/src/main/java/org/icedrobot/daneel/dex/ClassDef.java Sat Mar 19 23:37:56 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/ClassDef.java Sun Mar 20 19:31:39 2011 +0100 @@ -67,6 +67,8 @@ private String sourceFile; + private final AnnotationsDirectory annotations; + private ClassData classData; private ClassDef(ByteBuffer buffer, DexFile dex) { @@ -94,7 +96,14 @@ interfaces[i] = dex.getTypeDescriptor(buf.getShort()); } - // Parse the associated class_data_item structure. + // Parse associated annotations_directory_item structure. + if (annotationsOff != 0) { + ByteBuffer buf = dex.getDataBuffer(annotationsOff); + annotations = AnnotationsDirectory.parse(buf, dex); + } else + annotations = null; + + // Parse associated class_data_item structure. if (classDataOff != 0) { ByteBuffer buf = dex.getDataBuffer(classDataOff); classData = ClassData.parse(buf, dex, staticValuesOff);
--- a/src/main/java/org/icedrobot/daneel/dex/EncodedValue.java Sat Mar 19 23:37:56 2011 +0100 +++ b/src/main/java/org/icedrobot/daneel/dex/EncodedValue.java Sun Mar 20 19:31:39 2011 +0100 @@ -34,9 +34,14 @@ * you do not wish to do so, delete this exception statement from your * version. */ + package org.icedrobot.daneel.dex; import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; + +import org.icedrobot.daneel.util.BufferUtil; /** * A parser class capable of parsing {@code encoded_value} structures as part of @@ -94,6 +99,17 @@ case VALUE_STRING: assertValueArg(arg, 3); return dex.getString((int) readU64(buffer, arg)); + case VALUE_TYPE: + assertValueArg(arg, 3); + // XXX What kind of boxing should we use? + return "type@" + readU64(buffer, arg); + case VALUE_METHOD: + assertValueArg(arg, 3); + // XXX What kind of boxing should we use? + return "method@" + readU64(buffer, arg); + case VALUE_ARRAY: + assertValueArg(arg, 0); + return parseArray(buffer, dex); case VALUE_NULL: assertValueArg(arg, 0); return null; @@ -107,6 +123,42 @@ } /** + * Parses a {@code encoded_array} structure in a DEX file at the buffer's + * current position. + * + * @param buffer The byte buffer to read from. + * @param dex The DEX file currently being parsed. + * @return An object representing the parsed data. + */ + public static Object[] parseArray(ByteBuffer buffer, DexFile dex) { + int size = BufferUtil.getULEB128(buffer); + Object[] values = new Object[size]; + for (int i = 0; i < size; i++) + values[i] = parse(buffer, dex); + return values; + } + + /** + * Parses a {@code encoded_annotation} structure in a DEX file at the + * buffer's current position. + * + * @param buffer The byte buffer to read from. + * @param dex The DEX file currently being parsed. + * @return An object representing the parsed data. + */ + public static AnnotationValue parseAnnotation(ByteBuffer buffer, DexFile dex) { + int typeIdx = BufferUtil.getULEB128(buffer); + int size = BufferUtil.getULEB128(buffer); + String type = dex.getTypeDescriptor(typeIdx); + Map<String, Object> elements = new HashMap<String, Object>(size); + for (int i = 0; i < size; i++) { + int nameIdx = BufferUtil.getULEB128(buffer); + elements.put(dex.getString(nameIdx), parse(buffer, dex)); + } + return new AnnotationValue(type, elements); + } + + /** * Helper method for sanity checking the {@code value_arg} value. * * @param arg The given {@code value_arg} value. @@ -147,4 +199,23 @@ result |= (buffer.get() & 0xff) << (i * 8); return result; } + + /** + * An internal representation of an annotation as encoded in the {@code + * encoded_annotation} structure. + */ + static class AnnotationValue { + private final String type; + private final Map<String, Object> elements; + + public AnnotationValue(String type, Map<String, Object> elements) { + this.type = type; + this.elements = elements; + } + + @Override + public String toString() { + return '@' + type + '(' + elements + ')'; + } + }; }