package com.ibm.wala.dalvik.classLoader;
import java.util.Collection;
import java.util.Map;
import org.jf.dexlib.AnnotationItem;
import org.jf.dexlib.FieldIdItem;
import org.jf.dexlib.MethodIdItem;
import org.jf.dexlib.TypeIdItem;
import org.jf.dexlib.EncodedValue.AnnotationEncodedSubValue;
import org.jf.dexlib.EncodedValue.ArrayEncodedValue;
import org.jf.dexlib.EncodedValue.BooleanEncodedValue;
import org.jf.dexlib.EncodedValue.ByteEncodedValue;
import org.jf.dexlib.EncodedValue.CharEncodedValue;
import org.jf.dexlib.EncodedValue.DoubleEncodedValue;
import org.jf.dexlib.EncodedValue.EncodedValue;
import org.jf.dexlib.EncodedValue.EnumEncodedValue;
import org.jf.dexlib.EncodedValue.FieldEncodedValue;
import org.jf.dexlib.EncodedValue.FloatEncodedValue;
import org.jf.dexlib.EncodedValue.IntEncodedValue;
import org.jf.dexlib.EncodedValue.LongEncodedValue;
import org.jf.dexlib.EncodedValue.MethodEncodedValue;
import org.jf.dexlib.EncodedValue.ShortEncodedValue;
import org.jf.dexlib.EncodedValue.StringEncodedValue;
import org.jf.dexlib.EncodedValue.TypeEncodedValue;
import org.jf.dexlib.EncodedValue.ValueType;
import com.ibm.wala.shrikeCT.AnnotationsReader.AnnotationAttribute;
import com.ibm.wala.shrikeCT.AnnotationsReader.ArrayElementValue;
import com.ibm.wala.shrikeCT.AnnotationsReader.ConstantElementValue;
import com.ibm.wala.shrikeCT.AnnotationsReader.ElementValue;
import com.ibm.wala.shrikeCT.AnnotationsReader.EnumElementValue;
import com.ibm.wala.types.ClassLoaderReference;
import com.ibm.wala.types.Descriptor;
import com.ibm.wala.types.FieldReference;
import com.ibm.wala.types.MethodReference;
import com.ibm.wala.types.TypeName;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.types.annotations.Annotation;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.HashSetFactory;
import com.ibm.wala.util.strings.Atom;
import com.ibm.wala.util.strings.ImmutableByteArray;
public class DexUtil {
static Collection<Annotation> getAnnotations(Collection<AnnotationItem> as, ClassLoaderReference clr) {
Collection<Annotation> result = HashSetFactory.make();
for(AnnotationItem a : as) {
result.add(getAnnotation(a, clr));
}
return result;
}
static Annotation getAnnotation(AnnotationItem a, ClassLoaderReference clr) {
return getAnnotation(a.getEncodedAnnotation(), clr);
}
static Annotation getAnnotation(AnnotationEncodedSubValue ea, ClassLoaderReference clr) {
Map<String,ElementValue> values = HashMapFactory.make();
TypeReference at = getTypeRef(ea.annotationType, clr);
for(int i = 0; i < ea.names.length; i++) {
String name = ea.names[i].getStringValue();
EncodedValue v = ea.values[i];
ElementValue value = getValue(clr, v);
values.put(name, value);
}
return Annotation.makeWithNamed(at, values);
}
static ElementValue getValue(ClassLoaderReference clr, EncodedValue v) {
switch (v.getValueType()) {
case VALUE_ANNOTATION:
Annotation a = getAnnotation((AnnotationEncodedSubValue)v, clr);
return new AnnotationAttribute(a.getType().getName().toString() +";", a.getNamedArguments());
case VALUE_ARRAY:
EncodedValue[] vs = ((ArrayEncodedValue)v).values;
ElementValue rs[] = new ElementValue[ vs.length ];
for(int idx = 0; idx < vs.length; idx++) {
rs[idx] = getValue(clr, vs[idx]);
}
return new ArrayElementValue(rs);
case VALUE_BOOLEAN:
Boolean bl = ((BooleanEncodedValue)v).value;
return new ConstantElementValue(bl);
case VALUE_BYTE:
Byte bt = ((ByteEncodedValue)v).value;
return new ConstantElementValue(bt);
case VALUE_CHAR:
Character c = ((CharEncodedValue)v).value;
return new ConstantElementValue(c);
case VALUE_DOUBLE:
Double d = ((DoubleEncodedValue)v).value;
return new ConstantElementValue(d);
case VALUE_ENUM:
FieldIdItem o = ((EnumEncodedValue)v).value;
return new EnumElementValue(o.getFieldType().getTypeDescriptor(), o.getFieldName().getStringValue());
case VALUE_FIELD:
o = v.getValueType()==ValueType.VALUE_ENUM? ((EnumEncodedValue)v).value: ((FieldEncodedValue)v).value;
String fieldName = o.getFieldName().getStringValue();
TypeReference ft = getTypeRef(o.getFieldType(), clr);
TypeReference ct = getTypeRef(o.getContainingClass(), clr);
return new ConstantElementValue(FieldReference.findOrCreate(ct, Atom.findOrCreateUnicodeAtom(fieldName), ft));
case VALUE_FLOAT:
Float f = ((FloatEncodedValue)v).value;
return new ConstantElementValue(f);
case VALUE_INT:
Integer iv = ((IntEncodedValue)v).value;
return new ConstantElementValue(iv);
case VALUE_LONG:
Long l = ((LongEncodedValue)v).value;
return new ConstantElementValue(l);
case VALUE_METHOD:
MethodIdItem m = ((MethodEncodedValue)v).value;
ct = getTypeRef(m.getContainingClass(), clr);
String methodName = m.getMethodName().getStringValue();
String methodSig = m.getPrototype().getPrototypeString();
return new ConstantElementValue(MethodReference.findOrCreate(ct, Atom.findOrCreateUnicodeAtom(methodName), Descriptor.findOrCreateUTF8(methodSig)));
case VALUE_NULL:
return new ConstantElementValue(null);
case VALUE_SHORT:
Short s = ((ShortEncodedValue)v).value;
return new ConstantElementValue(s);
case VALUE_STRING:
String str = ((StringEncodedValue)v).value.getStringValue();
return new ConstantElementValue(str);
case VALUE_TYPE:
TypeIdItem t = ((TypeEncodedValue)v).value;
return new ConstantElementValue(getTypeName(t) + ";");
default:
assert false : v;
return null;
}
}
static TypeReference getTypeRef(TypeIdItem type, ClassLoaderReference clr) {
return TypeReference.findOrCreate(clr, getTypeName(type));
}
static TypeName getTypeName(TypeIdItem fieldType) {
ImmutableByteArray fieldTypeArray = ImmutableByteArray.make(fieldType.getTypeDescriptor());
TypeName T = null;
if (fieldTypeArray.get(fieldTypeArray.length() - 1) == ';') {
T = TypeName.findOrCreate(fieldTypeArray, 0, fieldTypeArray.length() - 1);
} else {
T = TypeName.findOrCreate(fieldTypeArray);
}
return T;
}
}