// CustomAttribute.cpp #include "stdj2cpp.h" #include "ArrayType.h" #include "Boolean.h" #include "Byte.h" #include "ByteBuffer.h" #include "CSharpKeywords.h" #include "Character.h" #include "Class.h" #include "ClassWriter.h" #include "Double.h" #include "Float.h" #include "ILAsmKeywords.h" #include "ILAsmWriter.h" #include "Integer.h" #include "Long.h" #include "Main.h" #include "ManagedCppWriter.h" #include "MemberInfo.h" #include "MemberRef.h" #include "MethodInfo.h" #include "ModuleInfo.h" #include "Name.h" #include "NamedArg.h" #include "ParameterInfo.h" #include "PrintStream.h" #include "Short.h" #include "SignatureInfo.h" #include "System.h" #include "Type.h" #include "TypeInfo.h" #include "TypeValue.h" #include "CustomAttribute.h" /** Decompile a custom attribute */ CustomAttribute::CustomAttribute(int mdMethodRef, Array* args, Array* namedArgs, Object* target) : Object() , classfile(null) { methodRefToken = mdMethodRef; this->args = args; this->namedArgs = namedArgs; this->target = target; classfile = getTypeInfo(target); constructor = classfile->getMethodRef(methodRefToken); } TypeInfo* CustomAttribute::getTypeInfo(Object* target) { TypeInfo* typedef_ = null; if (instanceof(target, TypeInfo)) { typedef_ = (TypeInfo*)target; } else if (instanceof(target, MemberInfo)) { typedef_ = (((MemberInfo*)target))->getDeclaringType(); } else if (instanceof(target, ParameterInfo)) { typedef_ = (((ParameterInfo*)target)->parent)->getDeclaringType(); } else if (instanceof(target, ModuleInfo)) { typedef_ = (((ModuleInfo*)target))->getGlobalType(); } else { (System::err)->println(StringBuffer("CustomAttribute target yet to handle: ") + (target->getClass())->getName()); } return typedef_; } Array* CustomAttribute::getArgs() { return args; } Array* CustomAttribute::getNamedArgs() { return namedArgs; } void CustomAttribute::emitStringAsILAsm(ByteBuffer* buf, String str) { if (str == null) { buf->appendByte(-1); return; } int len = str.length(); if (len <= 127) { buf->appendByte((jbyte)len); } else if (len <= 16383) { buf->appendByte((jbyte)(len >> (int)8 | 128)); buf->appendByte((jbyte)(len & 255)); } else { buf->appendByte((jbyte)(len >> (int)24 | 192)); buf->appendByte((jbyte)(len >> (int)16 & 255)); buf->appendByte((jbyte)(len >> (int)8 & 255)); buf->appendByte((jbyte)(len & 255)); } Name* nm = Name::fromString(str); Array* utfs = nm->toUtf(); buf->appendBytes(utfs); } /** write a constant value according to ILAsm custom attribute blob format */ void CustomAttribute::writeValueAsILAsm(ByteBuffer* tmp, Type* t, Object* val) { if (t->isBoolean()) { boolean z = (((Boolean*)val))->booleanValue(); tmp->appendByte((z) ? 1 : 0); } else if (t->isI1()) { jbyte b = (((Byte*)val))->byteValue(); tmp->appendByte(b); } else if (t->isU1()) { short s = (((Short*)val))->shortValue(); tmp->appendByte((jbyte)s); } else if (t->isChar()) { jchar c = (((Character*)val))->charValue(); tmp->appendCharWithLittleEndian(c); } else if (t->isU2()) { int n = (((Integer*)val))->intValue(); tmp->appendShortWithLittleEndian((short)n); } else if (t->isI2()) { short s = (((Short*)val))->shortValue(); tmp->appendShortWithLittleEndian(s); } else if (t->isI4()) { int n = (((Integer*)val))->intValue(); tmp->appendIntWithLittleEndian(n); } else if (t->isU4()) { jlong l = (((Long*)val))->longValue(); tmp->appendIntWithLittleEndian((int)l); } else if (t->isI8() || t->isU8()) { jlong l = (((Long*)val))->longValue(); tmp->appendLongWithLittleEndian(l); } else if (t->isR4()) { float f = (((Float*)val))->floatValue(); tmp->appendFloatWithLittleEndian(f); } else if (t->isR8()) { double d = (((Double*)val))->doubleValue(); tmp->appendDoubleWithLittleEndian(d); } else if (t->isString() || t->equals(Type::System_Type)) { emitStringAsILAsm(tmp, *(String*)val); } else if (t->isSZArray()) { Array* values = (Array*)val; if (values == null) { tmp->appendByte(-1); } else { tmp->appendIntWithLittleEndian(values->length); for (int i = 0; i < values->length ; i++) { writeValueAsILAsm(tmp, t->getElementType(), (*values)[i]); } } } else if (t->isValueType()) { TypeInfo* enumtype = t->loadDefinition(); Type* underlyingType = enumtype->getEnumUnderlyingType(); if (underlyingType == null) { underlyingType = Type::I4; } writeValueAsILAsm(tmp, underlyingType, val); } else if (t->isObject()) { TypeValue* tv = (TypeValue*)val; jbyte tc = tv->typecode; Object* value = tv->value; tmp->appendByte(tc); Type* serializedType = null; if (tc == remotesoft_cormd_TypeValue_SERIALIZATION_TYPE_TAGGED_OBJECT) { (System::err)->println("yet to handle: SERIALIZATION_TYPE_TAGGED_OBJECT."); } else if (tc == remotesoft_cormd_TypeValue_SERIALIZATION_TYPE_TYPE) { serializedType = Type::STRING; } else if (tc == remotesoft_cormd_TypeValue_SERIALIZATION_TYPE_ENUM) { String s = tv->enumTypename; emitStringAsILAsm(tmp, s); TypeInfo* enumtype = (ModuleInfo::currentAssembly)->loadType(s); Type* underlyingType = (enumtype != null) ? enumtype->getEnumUnderlyingType() : null; if (underlyingType == null) { underlyingType = Type::I4; } serializedType = underlyingType; value = tv->value; } else if (tc == remotesoft_cormd_Type_ELEMENT_TYPE_SZARRAY) { serializedType = new ArrayType(tc, Type::createSimpleType(tv->elemtypecode)); tmp->appendByte(tv->elemtypecode); } else { serializedType = Type::createSimpleType(tc); } writeValueAsILAsm(tmp, serializedType, value); } } /** Emit type for named arg */ void CustomAttribute::emitType(ByteBuffer* buf, Type* t) { jbyte typecode = t->typecode; buf->appendByte(typecode); if (typecode == remotesoft_cormd_TypeValue_SERIALIZATION_TYPE_ENUM) { emitStringAsILAsm(buf, t->getAssemblyQualifiedName()); } else if (typecode == remotesoft_cormd_Type_ELEMENT_TYPE_SZARRAY) { emitType(buf, t->getElementType()); } } void CustomAttribute::outputAsILAsm(ByteBuffer* buf) { buf->appendName(ILAsmKeywords::_custom); buf->appendByte(' '); constructor->outputAsILAsm(buf); buf->appendByte(' '); buf->appendByte('='); buf->appendByte(' '); buf->appendByte('('); ByteBuffer* tmp = new ByteBuffer(); tmp->appendShortWithLittleEndian((short)1); Array* argTypes = (constructor->getSignature())->getArgTypes(); for (int i = 0; i < argTypes->length ; i++) { Type* t = (*argTypes)[i]; writeValueAsILAsm(tmp, t, (*args)[i]); } tmp->appendShortWithLittleEndian((short)namedArgs->length); for (i = 0; i < namedArgs->length ; i++) { NamedArg* narg = (*namedArgs)[i]; tmp->appendByte(narg->kind); emitType(tmp, narg->type); writeValueAsILAsm(tmp, Type::STRING, &narg->name); writeValueAsILAsm(tmp, new Type(narg->typecode), narg->value); } ILAsmWriter::writeHexBytes(buf, tmp->elems, tmp->length); buf->appendByte(' '); buf->appendByte(')'); } void CustomAttribute::writeValue(ByteBuffer* buf, Type* t, Object* val) { if (t->equals(Type::System_Type)) { buf->appendName((ClassWriter::currentWriter)->mapKeyword(CSharpKeywords::_typeof)); buf->appendByte('('); String fullyQualifiedName = *(String*)val; int comma = fullyQualifiedName.indexOf(','); if (comma > 0) { fullyQualifiedName = fullyQualifiedName.substring(0, comma); } buf->appendString(classfile->toSimpleName(fullyQualifiedName)); buf->appendByte(')'); } else if (t->isSZArray()) { if (!Main::writer::isCPP()) { buf->appendName(CSharpKeywords::_new); buf->appendByte(' '); buf->appendString(t->toString()); } buf->appendByte('{'); Array* values = (Array*)val; for (int j = 0; j < values->length ; j++) { if (j != 0) { buf->appendByte(','); buf->appendByte(' '); } writeValue(buf, t->getElementType(), (*values)[j]); } buf->appendByte('}'); } else if (!t->isPrimitive() && t->isValueType() || t->typecode == remotesoft_cormd_TypeValue_SERIALIZATION_TYPE_ENUM) { if (instanceof(t, TypeInfo) && Main::writer::isCPP()) { ManagedCppWriter* writer = (ManagedCppWriter*)Main::writer; if (writer->hfile) { writer->insertHFileInclude((TypeInfo*)t); } } TypeInfo* enumtype = t->loadDefinition(); Type* underlyingType = (enumtype != null) ? enumtype->getEnumUnderlyingType() : null; if (underlyingType == null) { underlyingType = Type::I4; } if (enumtype != null) { buf->appendString(classfile->toSimpleName(enumtype)); if (Main::writer::isCPP()) { buf->appendAsciiString("::"); } else { buf->appendByte('.'); } buf->appendAsciiString((ClassWriter::currentWriter)->toLiteral(enumtype, val)); } else { writeValue(buf, underlyingType, val); } } else if (t->isObject()) { TypeValue* tv = (TypeValue*)val; jbyte tc = tv->typecode; Object* value = tv->value; Type* serializedType = null; if (tc == remotesoft_cormd_TypeValue_SERIALIZATION_TYPE_TAGGED_OBJECT) { (System::err)->println("yet to handle: SERIALIZATION_TYPE_TAGGED_OBJECT."); } else if (tc == remotesoft_cormd_TypeValue_SERIALIZATION_TYPE_TYPE) { serializedType = Type::System_Type; } else if (tc == remotesoft_cormd_TypeValue_SERIALIZATION_TYPE_ENUM) { String s = tv->enumTypename; TypeInfo* enumtype = (ModuleInfo::currentAssembly)->loadType(s); Type* underlyingType = (enumtype != null) ? enumtype->getEnumUnderlyingType() : null; if (underlyingType == null) { underlyingType = Type::I4; } if (enumtype != null) { classfile->registerType(enumtype); buf->appendString(classfile->toSimpleName(enumtype)); if (Main::writer::isCPP()) { buf->appendAsciiString("::"); } else { buf->appendByte('.'); } buf->appendAsciiString((ClassWriter::currentWriter)->toLiteral(enumtype, tv->value)); return; } serializedType = underlyingType; value = tv->value; } else if (tc == remotesoft_cormd_Type_ELEMENT_TYPE_SZARRAY) { serializedType = new ArrayType(tc, Type::createSimpleType(tv->elemtypecode)); } else { serializedType = Type::createSimpleType(tc); } writeValue(buf, serializedType, value); } else { if (t->isString() && val == null) { buf->appendAsciiString((ClassWriter::currentWriter)->nullLiteral()); } else { buf->appendAsciiString((ClassWriter::currentWriter)->toLiteral(t, val)); } } } /** Generate a C# rep, e.g., [MyAttribute("Christina", "Zhang")] */ void CustomAttribute::output(ByteBuffer* buf, boolean isReturnTarget) { if (ClassWriter::targetLanguage != remotesoft_salamander_ClassWriter_VB) { buf->appendByte('['); } if (isReturnTarget) { if (Main::writer::isCPP()) { buf->appendAsciiString("returnvalue: "); } else { buf->appendAsciiString("return: "); } } else if (classfile->isFakedGlobalType()) { buf->appendAsciiString("assembly: "); } output(buf); } /** Generate a C# rep, e.g., [MyAttribute("Christina", "Zhang")] */ void CustomAttribute::output(ByteBuffer* buf, String target) { if (ClassWriter::targetLanguage != remotesoft_salamander_ClassWriter_VB) { buf->appendByte('['); } buf->appendAsciiString(target); buf->appendByte(':'); buf->appendByte(' '); output(buf); } void CustomAttribute::output(ByteBuffer* buf) { buf->appendString(classfile->getFlatName(constructor->owner)); if (Main::writer::isCPP() && (constructor->getSignature())->getArgTypes()->length == 0 && namedArgs->length == 0) { buf->appendByte(']'); return; } buf->appendByte('('); Array* argTypes = (constructor->getSignature())->getArgTypes(); for (int i = 0; i < argTypes->length ; i++) { if (i != 0) { buf->appendByte(','); buf->appendByte(' '); } Type* t = (*argTypes)[i]; writeValue(buf, t, (*args)[i]); } boolean first = true; for (i = 0; i < namedArgs->length ; i++) { if (argTypes->length != 0 || !first) { buf->appendByte(','); buf->appendByte(' '); } first = false; NamedArg* narg = (*namedArgs)[i]; buf->appendString(narg->name); if (ClassWriter::targetLanguage == remotesoft_salamander_ClassWriter_VB) { buf->appendByte(':'); } buf->appendByte('='); writeValue(buf, narg->type, narg->value); } buf->appendByte(')'); if (ClassWriter::targetLanguage != remotesoft_salamander_ClassWriter_VB) { buf->appendByte(']'); } } /** Check if this is a System.ParamArrayAttribute */ boolean CustomAttribute::isParamArrayAttribute() { if ((constructor->owner)->equals(Type::ParamArrayAttribute)) { return (constructor->signature)->getArgTypes()->length == 0; } else { return false; } } /** Check if this is a System.ParamArrayAttribute */ boolean CustomAttribute::isDefaultMemberAttribute() { return (constructor->owner)->equals(Type::DefaultMemberAttribute); } /** Check if this is a System.Diagnostics.DebuggableAttribute */ boolean CustomAttribute::isDebuggableAttribute() { return (constructor->owner)->equals(Type::DebuggableAttribute); } /** Get the type that defines this attribute */ Type* CustomAttribute::getDeclaringType() { return constructor->owner; } Object* CustomAttribute::clone() { return new CustomAttribute(*this); }