package scouter.javassist.bytecode;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import scouter.javassist.bytecode.AnnotationsAttribute;
import scouter.javassist.bytecode.AttributeInfo;
import scouter.javassist.bytecode.ByteArray;
import scouter.javassist.bytecode.ConstPool;
import scouter.javassist.bytecode.annotation.TypeAnnotationsWriter;
/**
* A class representing
* {@code RuntimeVisibleTypeAnnotations} attribute and
* {@code RuntimeInvisibleTypeAnnotations} attribute.
*
* @since 3.19
*/
public class TypeAnnotationsAttribute extends AttributeInfo {
/**
* The name of the {@code RuntimeVisibleTypeAnnotations} attribute.
*/
public static final String visibleTag = "RuntimeVisibleTypeAnnotations";
/**
* The name of the {@code RuntimeInvisibleTypeAnnotations} attribute.
*/
public static final String invisibleTag = "RuntimeInvisibleTypeAnnotations";
/**
* Constructs a <code>Runtime(In)VisibleTypeAnnotations_attribute</code>.
*
* @param cp constant pool
* @param attrname attribute name (<code>visibleTag</code> or
* <code>invisibleTag</code>).
* @param info the contents of this attribute. It does not
* include <code>attribute_name_index</code> or
* <code>attribute_length</code>.
*/
public TypeAnnotationsAttribute(ConstPool cp, String attrname, byte[] info) {
super(cp, attrname, info);
}
/**
* @param n the attribute name.
*/
TypeAnnotationsAttribute(ConstPool cp, int n, DataInputStream in)
throws IOException
{
super(cp, n, in);
}
/**
* Returns <code>num_annotations</code>.
*/
public int numAnnotations() {
return ByteArray.readU16bit(info, 0);
}
/**
* Copies this attribute and returns a new copy.
*/
public AttributeInfo copy(ConstPool newCp, Map classnames) {
Copier copier = new Copier(info, constPool, newCp, classnames);
try {
copier.annotationArray();
return new TypeAnnotationsAttribute(newCp, getName(), copier.close());
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @param oldname a JVM class name.
* @param newname a JVM class name.
*/
void renameClass(String oldname, String newname) {
HashMap map = new HashMap();
map.put(oldname, newname);
renameClass(map);
}
void renameClass(Map classnames) {
Renamer renamer = new Renamer(info, getConstPool(), classnames);
try {
renamer.annotationArray();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
void getRefClasses(Map classnames) { renameClass(classnames); }
/**
* To visit each elements of the type annotation attribute,
* call {@code annotationArray()}.
*
* @see #annotationArray()
*/
static class TAWalker extends AnnotationsAttribute.Walker {
SubWalker subWalker;
TAWalker(byte[] attrInfo) {
super(attrInfo);
subWalker = new SubWalker(attrInfo);
}
int annotationArray(int pos, int num) throws Exception {
for (int i = 0; i < num; i++) {
int targetType = info[pos] & 0xff;
pos = subWalker.targetInfo(pos + 1, targetType);
pos = subWalker.typePath(pos);
pos = annotation(pos);
}
return pos;
}
}
static class SubWalker {
byte[] info;
SubWalker(byte[] attrInfo) {
info = attrInfo;
}
final int targetInfo(int pos, int type) throws Exception {
switch (type) {
case 0x00:
case 0x01: {
int index = info[pos] & 0xff;
typeParameterTarget(pos, type, index);
return pos + 1; }
case 0x10: {
int index = ByteArray.readU16bit(info, pos);
supertypeTarget(pos, index);
return pos + 2; }
case 0x11:
case 0x12: {
int param = info[pos] & 0xff;
int bound = info[pos + 1] & 0xff;
typeParameterBoundTarget(pos, type, param, bound);
return pos + 2; }
case 0x13:
case 0x14:
case 0x15:
emptyTarget(pos, type);
return pos;
case 0x16: {
int index = info[pos] & 0xff;
formalParameterTarget(pos, index);
return pos + 1; }
case 0x17: {
int index = ByteArray.readU16bit(info, pos);
throwsTarget(pos, index);
return pos + 2; }
case 0x40:
case 0x41: {
int len = ByteArray.readU16bit(info, pos);
return localvarTarget(pos + 2, type, len); }
case 0x42: {
int index = ByteArray.readU16bit(info, pos);
catchTarget(pos, index);
return pos + 2; }
case 0x43:
case 0x44:
case 0x45:
case 0x46: {
int offset = ByteArray.readU16bit(info, pos);
offsetTarget(pos, type, offset);
return pos + 2; }
case 0x47:
case 0x48:
case 0x49:
case 0x4a:
case 0x4b: {
int offset = ByteArray.readU16bit(info, pos);
int index = info[pos + 2] & 0xff;
typeArgumentTarget(pos, type, offset, index);
return pos + 3; }
default:
throw new RuntimeException("invalid target type: " + type);
}
}
void typeParameterTarget(int pos, int targetType, int typeParameterIndex)
throws Exception {}
void supertypeTarget(int pos, int superTypeIndex) throws Exception {}
void typeParameterBoundTarget(int pos, int targetType, int typeParameterIndex,
int boundIndex) throws Exception {}
void emptyTarget(int pos, int targetType) throws Exception {}
void formalParameterTarget(int pos, int formalParameterIndex) throws Exception {}
void throwsTarget(int pos, int throwsTypeIndex) throws Exception {}
int localvarTarget(int pos, int targetType, int tableLength) throws Exception {
for (int i = 0; i < tableLength; i++) {
int start = ByteArray.readU16bit(info, pos);
int length = ByteArray.readU16bit(info, pos + 2);
int index = ByteArray.readU16bit(info, pos + 4);
localvarTarget(pos, targetType, start, length, index);
pos += 6;
}
return pos;
}
void localvarTarget(int pos, int targetType, int startPc, int length, int index)
throws Exception {}
void catchTarget(int pos, int exceptionTableIndex) throws Exception {}
void offsetTarget(int pos, int targetType, int offset) throws Exception {}
void typeArgumentTarget(int pos, int targetType, int offset, int typeArgumentIndex)
throws Exception {}
final int typePath(int pos) throws Exception {
int len = info[pos++] & 0xff;
return typePath(pos, len);
}
int typePath(int pos, int pathLength) throws Exception {
for (int i = 0; i < pathLength; i++) {
int kind = info[pos] & 0xff;
int index = info[pos + 1] & 0xff;
typePath(pos, kind, index);
pos += 2;
}
return pos;
}
void typePath(int pos, int typePathKind, int typeArgumentIndex) throws Exception {}
}
static class Renamer extends AnnotationsAttribute.Renamer {
SubWalker sub;
Renamer(byte[] attrInfo, ConstPool cp, Map map) {
super(attrInfo, cp, map);
sub = new SubWalker(attrInfo);
}
int annotationArray(int pos, int num) throws Exception {
for (int i = 0; i < num; i++) {
int targetType = info[pos] & 0xff;
pos = sub.targetInfo(pos + 1, targetType);
pos = sub.typePath(pos);
pos = annotation(pos);
}
return pos;
}
}
static class Copier extends AnnotationsAttribute.Copier {
SubCopier sub;
Copier(byte[] attrInfo, ConstPool src, ConstPool dest, Map map) {
super(attrInfo, src, dest, map, false);
TypeAnnotationsWriter w = new TypeAnnotationsWriter(output, dest);
writer = w;
sub = new SubCopier(attrInfo, src, dest, map, w);
}
int annotationArray(int pos, int num) throws Exception {
writer.numAnnotations(num);
for (int i = 0; i < num; i++) {
int targetType = info[pos] & 0xff;
pos = sub.targetInfo(pos + 1, targetType);
pos = sub.typePath(pos);
pos = annotation(pos);
}
return pos;
}
}
static class SubCopier extends SubWalker {
ConstPool srcPool, destPool;
Map classnames;
TypeAnnotationsWriter writer;
SubCopier(byte[] attrInfo, ConstPool src, ConstPool dest, Map map,
TypeAnnotationsWriter w)
{
super(attrInfo);
srcPool = src;
destPool = dest;
classnames = map;
writer = w;
}
void typeParameterTarget(int pos, int targetType, int typeParameterIndex)
throws Exception
{
writer.typeParameterTarget(targetType, typeParameterIndex);
}
void supertypeTarget(int pos, int superTypeIndex) throws Exception {
writer.supertypeTarget(superTypeIndex);
}
void typeParameterBoundTarget(int pos, int targetType, int typeParameterIndex,
int boundIndex)
throws Exception
{
writer.typeParameterBoundTarget(targetType, typeParameterIndex, boundIndex);
}
void emptyTarget(int pos, int targetType) throws Exception {
writer.emptyTarget(targetType);
}
void formalParameterTarget(int pos, int formalParameterIndex) throws Exception {
writer.formalParameterTarget(formalParameterIndex);
}
void throwsTarget(int pos, int throwsTypeIndex) throws Exception {
writer.throwsTarget(throwsTypeIndex);
}
int localvarTarget(int pos, int targetType, int tableLength) throws Exception {
writer.localVarTarget(targetType, tableLength);
return super.localvarTarget(pos, targetType, tableLength);
}
void localvarTarget(int pos, int targetType, int startPc, int length, int index)
throws Exception
{
writer.localVarTargetTable(startPc, length, index);
}
void catchTarget(int pos, int exceptionTableIndex) throws Exception {
writer.catchTarget(exceptionTableIndex);
}
void offsetTarget(int pos, int targetType, int offset) throws Exception {
writer.offsetTarget(targetType, offset);
}
void typeArgumentTarget(int pos, int targetType, int offset, int typeArgumentIndex)
throws Exception
{
writer.typeArgumentTarget(targetType, offset, typeArgumentIndex);
}
int typePath(int pos, int pathLength) throws Exception {
writer.typePath(pathLength);
return super.typePath(pos, pathLength);
}
void typePath(int pos, int typePathKind, int typeArgumentIndex) throws Exception {
writer.typePathPath(typePathKind, typeArgumentIndex);
}
}
}