/**
* AnnotationElement are used by Annotation attributes
* @author $Author: Iouri Kharon $
* @version $Revision: 1.0 $
*/
package jas;
import java.io.*;
import java.util.Vector;
import java.util.Enumeration;
public class AnnotationElement
{
private boolean array;
private char sign;
private CP name, exttype;
private Vector values;
private static final char type_int = 'I'; // integer
private static final char type_byte = 'B'; // signed byte
private static final char type_char = 'C'; // unicode character
private static final char type_short = 'S'; // signed short
private static final char type_bool = 'Z'; // boolean true or false
// end of int types
private static final char type_float = 'F'; // single precision IEEE foat
private static final char type_double = 'D'; // double precision IEEE float
private static final char type_long = 'J'; // long integer
//prefix
private static final char type_array = '[';
//annotation special
private static final char type_string = 's'; // constant string
private static final char type_class = 'c'; // return type descriptor
//complex types
private static final char type_enum = 'e'; // enum constant (type + name)
private static final char type_annot = '@'; // nested annotation
private static void badsignature() throws jasError
{ throw new jasError("invalid type signature for annotation field"); }
public AnnotationElement(String name, String type, String exttype)
throws jasError
{
this.name = null;
if(name != null) this.name = new AsciiCP(name);
values = new Vector();
array = false;
sign = type.charAt(0);
if(sign != type_array) {
if(type.length() != 1) badsignature();
} else {
array = true;
if(type.length() != 2) badsignature();
sign = type.charAt(1);
}
switch(sign) {
default:
badsignature();
case type_enum:
case type_annot:
if(exttype == null) badsignature();
this.exttype = new AsciiCP(exttype);
break;
case type_int:
case type_byte:
case type_char:
case type_short:
case type_bool:
case type_float:
case type_double:
case type_long:
case type_string:
case type_class:
if(exttype != null) badsignature();
this.exttype = null;
break;
}
}
void addValue(Object value) throws jasError
{
if(value == null) Annotation.ParserError();
if(!array && values.size() != 0)
throw new jasError("too many values for nonarray annotation field type");
CP cp = null;
switch(sign) {
case type_char:
case type_bool:
case type_byte:
case type_short:
case type_int:
if(value instanceof Integer) {
int val = ((Integer)value).intValue();
boolean badval = false;
switch(sign) {
case type_bool:
if(val < 0 || val > 1) badval = true;
break;
case type_char:
if(val < 0 || val > 0xFFFF) badval = true;
break;
case type_byte:
if(val < -128 || val > 127) badval = true;
case type_short:
if(val < -32768 || val > 32767) badval = true;
default: // type_int
break;
}
if(badval)
throw new jasError("annotation field value exceed range of type", true);
cp = new IntegerCP(val);
}
break;
case type_float:
if(value instanceof Float)
cp = new FloatCP(((Float)value).floatValue());
break;
case type_double:
if(value instanceof Double) {
cp = new DoubleCP(((Double)value).doubleValue());
} else if(value instanceof Float) {
cp = new DoubleCP(((Float)value).floatValue());
}
break;
case type_long:
if(value instanceof Long) {
cp = new LongCP(((Long)value).longValue());
} else if(value instanceof Integer) {
cp = new LongCP(((Integer)value).intValue());
}
break;
case type_string:
case type_class:
case type_enum:
if(value instanceof String)
cp = new AsciiCP((String)value);
break;
case type_annot:
if(value instanceof Annotation)
cp = (Annotation)value;
default:
break;
}
if(cp == null)
throw new jasError("incompatible value for annotation field type");
values.add(cp);
}
public AsciiCP nestType() throws jasError
{
if(sign != type_annot) Annotation.ParserError();
return((AsciiCP)exttype);
}
public void done() throws jasError
{
switch(values.size()) {
case 1:
return;
default:
if(array) return;
//pass thru
case 0:
Annotation.ParserError();
}
}
void resolve(ClassEnv e)
{
if(name != null) e.addCPItem(name);
if(sign == type_enum) e.addCPItem(exttype);
for(Enumeration en = values.elements(); en.hasMoreElements(); ) {
CP cp = ((CP)en.nextElement());
if(sign != type_annot) e.addCPItem(cp);
else cp.resolve(e);
}
}
int size() throws jasError
{
done();
int len;
if(sign == type_annot) {
len = values.size(); // tags
for(Enumeration en = values.elements(); en.hasMoreElements(); )
len += ((Annotation)en.nextElement()).size();
} else {
len = 1+2;
if(sign == type_enum) len += 2;
len *= values.size();
}
if(array) len += 1+2;
if(name != null) len += 2;
return(len);
}
void write(ClassEnv e, DataOutputStream out) throws IOException, jasError
{
done();
if(name != null) out.writeShort(e.getCPIndex(name));
if(array) {
out.writeByte(type_array);
out.writeShort((short)values.size());
}
short id = 0;
if(sign == type_enum) id = e.getCPIndex(exttype);
for(Enumeration en = values.elements(); en.hasMoreElements(); ) {
out.writeByte(sign);
CP cp = ((CP)en.nextElement());
switch(sign) {
case type_annot:
((Annotation)cp).write(e, out);
break;
case type_enum:
out.writeShort(id);
//pass thru
default:
out.writeShort(e.getCPIndex(cp));
break;
}
}
}
}