FileDocCategorySizeDatePackage
AnnotationParser.javaAPI DocAndroid 1.5 API15117Wed May 06 22:41:02 BST 2009com.android.dx.cf.direct

AnnotationParser

public final class AnnotationParser extends Object
Parser for annotations.

Fields Summary
private final DirectClassFile
cf
non-null; class file being parsed
private final com.android.dx.rop.cst.ConstantPool
pool
non-null; constant pool to use
private final com.android.dx.util.ByteArray
bytes
non-null; bytes of the attribute data
private final com.android.dx.cf.iface.ParseObserver
observer
null-ok; parse observer, if any
private final ByteArray.MyDataInputStream
input
non-null; input stream to parse from
private int
parseCursor
non-null; cursor for use when informing the observer of what was parsed
Constructors Summary
public AnnotationParser(DirectClassFile cf, int offset, int length, com.android.dx.cf.iface.ParseObserver observer)
Constructs an instance.

param
cf non-null; class file to parse from
param
offset >= 0; offset into the class file data to parse at
param
length >= 0; number of bytes left in the attribute data
param
observer null-ok; parse observer to notify, if any

        if (cf == null) {
            throw new NullPointerException("cf == null");
        }

        this.cf = cf;
        this.pool = cf.getConstantPool();
        this.observer = observer;
        this.bytes = cf.getBytes().slice(offset, offset + length);
        this.input = bytes.makeDataInputStream();
        this.parseCursor = 0;
    
Methods Summary
private voidchangeIndent(int indent)
Convenience wrapper that simply calls through to observer.changeIndent().

param
indent the amount to change the indent by

        observer.changeIndent(indent);
    
private com.android.dx.rop.annotation.AnnotationparseAnnotation(com.android.dx.rop.annotation.AnnotationVisibility visibility)
Parses a single annotation.

param
visibility non-null; visibility of the parsed annotation
return
non-null; the parsed annotation

        requireLength(4);

        int typeIndex = input.readUnsignedShort();
        int numElements = input.readUnsignedShort();
        CstUtf8 typeUtf8 = (CstUtf8) pool.get(typeIndex);
        CstType type = new CstType(Type.intern(typeUtf8.getString()));

        if (observer != null) {
            parsed(2, "type: " + type.toHuman());
            parsed(2, "num_elements: " + numElements);
        }

        Annotation annotation = new Annotation(type, visibility);

        for (int i = 0; i < numElements; i++) {
            if (observer != null) {
                parsed(0, "elements[" + i + "]:");
                changeIndent(1);
            }

            NameValuePair element = parseElement();
            annotation.add(element);

            if (observer != null) {
                changeIndent(-1);
            }
        }

        annotation.setImmutable();
        return annotation;
    
public com.android.dx.rop.annotation.AnnotationsparseAnnotationAttribute(com.android.dx.rop.annotation.AnnotationVisibility visibility)
Parses an annotation attribute, per se.

param
visibility non-null; visibility of the parsed annotations
return
non-null; the list of annotations read from the attribute data

        Annotations result;
        
        try {
            result = parseAnnotations(visibility);

            if (input.available() != 0) {
                throw new ParseException("extra data in attribute");
            }
        } catch (IOException ex) {
            // ByteArray.MyDataInputStream should never throw.
            throw new RuntimeException("shouldn't happen", ex);
        }

        return result;
    
private com.android.dx.rop.annotation.AnnotationsparseAnnotations(com.android.dx.rop.annotation.AnnotationVisibility visibility)
Parses an annotation list.

param
visibility non-null; visibility of the parsed annotations
return
non-null; the list of annotations read from the attribute data

        int count = input.readUnsignedShort();

        if (observer != null) {
            parsed(2, "num_annotations: " + Hex.u2(count));
        }

        Annotations annotations = new Annotations();

        for (int i = 0; i < count; i++) {
            if (observer != null) {
                parsed(0, "annotations[" + i + "]:");
                changeIndent(1);
            }

            Annotation annotation = parseAnnotation(visibility);
            annotations.add(annotation);

            if (observer != null) {
                observer.changeIndent(-1);
            }
        }

        annotations.setImmutable();
        return annotations;
    
private com.android.dx.rop.annotation.AnnotationsListparseAnnotationsList(com.android.dx.rop.annotation.AnnotationVisibility visibility)
Parses a list of annotation lists.

param
visibility non-null; visibility of the parsed annotations
return
non-null; the list of annotation lists read from the attribute data

        int count = input.readUnsignedByte();

        if (observer != null) {
            parsed(1, "num_parameters: " + Hex.u1(count));
        }

        AnnotationsList outerList = new AnnotationsList(count);

        for (int i = 0; i < count; i++) {
            if (observer != null) {
                parsed(0, "parameter_annotations[" + i + "]:");
                changeIndent(1);
            }

            Annotations annotations = parseAnnotations(visibility);
            outerList.set(i, annotations);

            if (observer != null) {
                observer.changeIndent(-1);
            }
        }

        outerList.setImmutable();
        return outerList;
    
private com.android.dx.rop.cst.ConstantparseConstant()
Helper for {@link #parseValue}, which parses a constant reference and returns the referred-to constant value.

return
non-null; the parsed value

        int constValueIndex = input.readUnsignedShort();
        Constant value = (Constant) pool.get(constValueIndex);

        if (observer != null) {
            String human = (value instanceof CstUtf8) 
                ? ((CstUtf8) value).toQuoted() 
                : value.toHuman();
            parsed(2, "constant_value: " + human);
        }

        return value;
    
private com.android.dx.rop.annotation.NameValuePairparseElement()
Parses a {@link NameValuePair}.

return
non-null; the parsed element

        requireLength(5);
                
        int elementNameIndex = input.readUnsignedShort();
        CstUtf8 elementName = (CstUtf8) pool.get(elementNameIndex);
                
        if (observer != null) {
            parsed(2, "element_name: " + elementName.toHuman());
            parsed(0, "value: ");
            changeIndent(1);
        }

        Constant value = parseValue();

        if (observer != null) {
            changeIndent(-1);
        }

        return new NameValuePair(elementName, value);
    
public com.android.dx.rop.annotation.AnnotationsListparseParameterAttribute(com.android.dx.rop.annotation.AnnotationVisibility visibility)
Parses a parameter annotation attribute.

param
visibility non-null; visibility of the parsed annotations
return
non-null; the parsed list of lists of annotations

        AnnotationsList result;
        
        try {
            result = parseAnnotationsList(visibility);

            if (input.available() != 0) {
                throw new ParseException("extra data in attribute");
            }
        } catch (IOException ex) {
            // ByteArray.MyDataInputStream should never throw.
            throw new RuntimeException("shouldn't happen", ex);
        }

        return result;
    
private com.android.dx.rop.cst.ConstantparseValue()
Parses an annotation value.

return
non-null; the parsed value

        int tag = input.readUnsignedByte();

        if (observer != null) {
            CstUtf8 humanTag = new CstUtf8(Character.toString((char) tag));
            parsed(1, "tag: " + humanTag.toQuoted());
        }

        switch (tag) {
            case 'B": {
                CstInteger value = (CstInteger) parseConstant();
                return CstByte.make(value.getValue());
            }
            case 'C": {
                CstInteger value = (CstInteger) parseConstant();
                int intValue = value.getValue();
                return CstChar.make(value.getValue());
            }
            case 'D": {
                CstDouble value = (CstDouble) parseConstant();
                return value;
            }
            case 'F": {
                CstFloat value = (CstFloat) parseConstant();
                return value;
            }
            case 'I": {
                CstInteger value = (CstInteger) parseConstant();
                return value;
            }
            case 'J": {
                CstLong value = (CstLong) parseConstant();
                return value;
            }
            case 'S": {
                CstInteger value = (CstInteger) parseConstant();
                return CstShort.make(value.getValue());
            }
            case 'Z": {
                CstInteger value = (CstInteger) parseConstant();
                return CstBoolean.make(value.getValue());
            }
            case 'c": {
                int classInfoIndex = input.readUnsignedShort();
                CstUtf8 value = (CstUtf8) pool.get(classInfoIndex);
                Type type = Type.internReturnType(value.getString());
                
                if (observer != null) {
                    parsed(2, "class_info: " + type.toHuman());
                }

                return new CstType(type);
            }
            case 's": {
                CstString value = new CstString((CstUtf8) parseConstant());
                return value;
            }
            case 'e": {
                requireLength(4);

                int typeNameIndex = input.readUnsignedShort();
                int constNameIndex = input.readUnsignedShort();
                CstUtf8 typeName = (CstUtf8) pool.get(typeNameIndex);
                CstUtf8 constName = (CstUtf8) pool.get(constNameIndex);
                
                if (observer != null) {
                    parsed(2, "type_name: " + typeName.toHuman());
                    parsed(2, "const_name: " + constName.toHuman());
                }

                return new CstEnumRef(new CstNat(constName, typeName));
            }
            case '@": {
                Annotation annotation =
                    parseAnnotation(AnnotationVisibility.EMBEDDED);
                return new CstAnnotation(annotation);
            }
            case '[": {
                requireLength(2);

                int numValues = input.readUnsignedShort();
                CstArray.List list = new CstArray.List(numValues);

                if (observer != null) {
                    parsed(2, "num_values: " + numValues);
                    changeIndent(1);
                }

                for (int i = 0; i < numValues; i++) {
                    if (observer != null) {
                        changeIndent(-1);
                        parsed(0, "element_value[" + i + "]:");
                        changeIndent(1);
                    }
                    list.set(i, parseValue());
                }

                if (observer != null) {
                    changeIndent(-1);
                }

                list.setImmutable();
                return new CstArray(list);
            }
            default: {
                throw new ParseException("unknown annotation tag: " +
                        Hex.u1(tag));
            }
        }
    
public com.android.dx.rop.cst.ConstantparseValueAttribute()
Parses an annotation value (element_value) attribute.

return
non-null; the parsed constant value

        Constant result;
        
        try {
            result = parseValue();

            if (input.available() != 0) {
                throw new ParseException("extra data in attribute");
            }
        } catch (IOException ex) {
            // ByteArray.MyDataInputStream should never throw.
            throw new RuntimeException("shouldn't happen", ex);
        }

        return result;
    
private voidparsed(int length, java.lang.String message)
Helper which indicates that some bytes were just parsed. This should only be used (for efficiency sake) if the parse is known to be observed.

param
length >= 0; number of bytes parsed
param
message non-null; associated message

        observer.parsed(bytes, parseCursor, length, message);
        parseCursor += length;
    
private voidrequireLength(int requiredLength)
Helper which will throw an exception if the given number of bytes is not available to be read.

param
requiredLength the number of required bytes

        if (input.available() < requiredLength) {
            throw new ParseException("truncated annotation attribute");
        }