/*
* Copyright 2004-2010 Brian S O'Neill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.cojen.classfile;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.cojen.classfile.attribute.CodeAttr;
import org.cojen.classfile.attribute.ConstantValueAttr;
import org.cojen.classfile.attribute.DeprecatedAttr;
import org.cojen.classfile.attribute.EnclosingMethodAttr;
import org.cojen.classfile.attribute.ExceptionsAttr;
import org.cojen.classfile.attribute.InnerClassesAttr;
import org.cojen.classfile.attribute.LineNumberTableAttr;
import org.cojen.classfile.attribute.LocalVariableTableAttr;
import org.cojen.classfile.attribute.RuntimeInvisibleAnnotationsAttr;
import org.cojen.classfile.attribute.RuntimeInvisibleParameterAnnotationsAttr;
import org.cojen.classfile.attribute.RuntimeVisibleAnnotationsAttr;
import org.cojen.classfile.attribute.RuntimeVisibleParameterAnnotationsAttr;
import org.cojen.classfile.attribute.SignatureAttr;
import org.cojen.classfile.attribute.SourceFileAttr;
import org.cojen.classfile.attribute.StackMapTableAttr;
import org.cojen.classfile.attribute.SyntheticAttr;
import org.cojen.classfile.attribute.UnknownAttr;
import org.cojen.classfile.constant.ConstantUTFInfo;
/**
* This class corresponds to the attribute_info structure defined in section
* 4.7 of <i>The Java Virtual Machine Specification</i>.
*
* @author Brian S O'Neill
* @see ClassFile
*/
public abstract class Attribute {
final static Attribute[] NO_ATTRIBUTES = new Attribute[0];
public static final String CODE = "Code";
public static final String CONSTANT_VALUE = "ConstantValue";
public static final String DEPRECATED = "Deprecated";
public static final String EXCEPTIONS = "Exceptions";
public static final String INNER_CLASSES = "InnerClasses";
public static final String LINE_NUMBER_TABLE = "LineNumberTable";
public static final String LOCAL_VARIABLE_TABLE = "LocalVariableTable";
public static final String SOURCE_FILE = "SourceFile";
public static final String SYNTHETIC = "Synthetic";
public static final String SIGNATURE = "Signature";
public static final String ENCLOSING_METHOD = "EnclosingMethod";
public static final String RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations";
public static final String RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations";
public static final String RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS =
"RuntimeVisibleParamaterAnnotations";
public static final String RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS =
"RuntimeInvisibleParamaterAnnotations";
public static final String STACK_MAP_TABLE = "StackMapTable";
/** The ConstantPool that this attribute is defined against. */
private final ConstantPool mCp;
private String mName;
private ConstantUTFInfo mNameConstant;
protected Attribute(ConstantPool cp, String name) {
mCp = cp;
mName = name;
mNameConstant = cp.addConstantUTF(name);
}
/**
* Returns the ConstantPool that this attribute is defined against.
*/
public ConstantPool getConstantPool() {
return mCp;
}
/**
* Returns the name of this attribute.
*/
public String getName() {
return mName;
}
public ConstantUTFInfo getNameConstant() {
return mNameConstant;
}
/**
* Some attributes have sub-attributes. Default implementation returns an
* empty array.
*/
public Attribute[] getAttributes() {
return NO_ATTRIBUTES;
}
/**
* Returns the length (in bytes) of this attribute in the class file.
*/
public abstract int getLength();
/**
* This method writes the 16 bit name constant index followed by the
* 32 bit attribute length, followed by the attribute specific data.
*/
public void writeTo(DataOutput dout) throws IOException {
dout.writeShort(mNameConstant.getIndex());
dout.writeInt(getLength());
writeDataTo(dout);
}
/**
* Write just the attribute specific data. The default implementation
* writes nothing.
*/
public void writeDataTo(DataOutput dout) throws IOException {
}
/**
* @param attrFactory optional factory for reading custom attributes
*/
public static Attribute readFrom(ConstantPool cp,
DataInput din,
AttributeFactory attrFactory)
throws IOException
{
int index = din.readUnsignedShort();
String name = ((ConstantUTFInfo)cp.getConstant(index)).getValue();
int length = din.readInt();
attrFactory = new Factory(attrFactory);
return attrFactory.createAttribute(cp, name, length, din);
}
private static class Factory implements AttributeFactory {
private final AttributeFactory mAttrFactory;
public Factory(AttributeFactory attrFactory) {
mAttrFactory = attrFactory;
}
public Attribute createAttribute(ConstantPool cp,
String name,
int length,
DataInput din) throws IOException {
if (name.length() > 0) {
switch (name.charAt(0)) {
case 'C':
if (name.equals(CODE)) {
return new CodeAttr(cp, name, length, din, mAttrFactory);
} else if (name.equals(CONSTANT_VALUE)) {
return new ConstantValueAttr(cp, name, length, din);
}
break;
case 'D':
if (name.equals(DEPRECATED)) {
return new DeprecatedAttr(cp, name, length, din);
}
break;
case 'E':
if (name.equals(EXCEPTIONS)) {
return new ExceptionsAttr(cp, name, length, din);
} else if (name.equals(ENCLOSING_METHOD)) {
return new EnclosingMethodAttr(cp, name, length, din);
}
break;
case 'I':
if (name.equals(INNER_CLASSES)) {
return new InnerClassesAttr(cp, name, length, din);
}
break;
case 'L':
if (name.equals(LINE_NUMBER_TABLE)) {
return new LineNumberTableAttr(cp, name, length, din);
} else if (name.equals(LOCAL_VARIABLE_TABLE)) {
return new LocalVariableTableAttr(cp, name, length, din);
}
break;
case 'R':
if (name.equals(RUNTIME_VISIBLE_ANNOTATIONS)) {
return new RuntimeVisibleAnnotationsAttr(cp, name, length, din);
} else if (name.equals(RUNTIME_INVISIBLE_ANNOTATIONS)) {
return new RuntimeInvisibleAnnotationsAttr(cp, name, length, din);
} else if (name.equals(RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS)) {
return new RuntimeVisibleParameterAnnotationsAttr(cp, name, length, din);
} else if (name.equals(RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS)) {
return new RuntimeInvisibleParameterAnnotationsAttr(cp, name, length, din);
}
break;
case 'S':
if (name.equals(SOURCE_FILE)) {
return new SourceFileAttr(cp, name, length, din);
} else if (name.equals(SYNTHETIC)) {
return new SyntheticAttr(cp, name, length, din);
} else if (name.equals(SIGNATURE)) {
return new SignatureAttr(cp, name, length, din);
} else if (name.equals(STACK_MAP_TABLE)) {
return new StackMapTableAttr(cp, name, length, din);
}
break;
}
}
if (mAttrFactory != null) {
Attribute attr = mAttrFactory.createAttribute(cp, name, length, din);
if (attr != null) {
return attr;
}
}
// Default case, return attribute that captures the data, but
// doesn't decode it.
return new UnknownAttr(cp, name, length, din);
}
}
}