Hi Eyal, Thanks for working on this. I don't want to commit it as it is, but I'll surely use part of it. I don't want to load the assembly referenced only for reading a custom attribute body. Instead, I'll create an interface that CustomAttribute and SecurityDeclaration will share, and will allow one to load the content of something that needs to load a reference.
Something like: CustomAttribute ca = ...; if (!ca.Read) { ca.ForceRead (); } Otherwise, for a lot of assemblies, Cecil will have to load the corelib while the user don't necessary need to read the content of the custom attribute. Jb Eyal Alaluf wrote: > Hi, JB. > > Attached is patch for supporting enums in cutom attributes. Support is > added > for enums as ctor parameters as fields and as properties. > > The main problem with Enums is to identify their underlying integral type. > Without this integral type the custom attribute cannot be read. The patch > uses the assembly resolver for this purpose. > > I have attached a simple test scenraio with 3 C# files. > * Test1.cs is a DLL defining enums and an attribute that has enums as > field properties and ctor params. > * Test2.cs is another DLL that uses the attribute and enums from Test1. > This exercise the new code that resolves enum types from another DLL. > * ReadTest2.cs is an EXE written using Cecil that parses test2.dll and > prints the custom attributes of its types. It gets as argument the > path > to the dll it parses. > Note that Test1 uses ClassUsageAttaribute from mscorlib. For some reason > the > assembly resolver didn't find mscorlib.dll from the GAC when I ran > ReadTest2 > on Test2 until I put mscorlib.dll in the same dir as Test2 & ReadTest2. > > Eyal. > > > ------------------------------------------------------------------------ > > Index: Mono.Cecil/ReflectionReader.cs > =================================================================== > --- Mono.Cecil/ReflectionReader.cs (revision 66216) > +++ Mono.Cecil/ReflectionReader.cs (working copy) > @@ -65,7 +65,24 @@ > protected CodeReader m_codeReader; > protected ISymbolReader m_symbolReader; > > - public ModuleDefinition Module { > + internal AssemblyNameReference Corlib > + { > + get > + { > + if (m_corlib == null) { > + foreach (AssemblyNameReference ar in > m_module.AssemblyReferences) { > + if (ar.Name == > Constants.Corlib) { > + m_corlib = ar; > + break; > + } > + } > + } > + return m_corlib; > + } > + } > + > + public ModuleDefinition Module > + { > get { return m_module; } > } > > @@ -295,19 +312,11 @@ > > TypeReference coreType = m_module.TypeReferences > [fullName]; > if (coreType == null) { > - if (m_corlib == null) { > - foreach (AssemblyNameReference ar in > m_module.AssemblyReferences) { > - if (ar.Name == > Constants.Corlib) { > - m_corlib = ar; > - break; > - } > - } > - } > > string [] parts = fullName.Split ('.'); > if (parts.Length != 2) > throw new ReflectionException ("Unvalid > core type name"); > - coreType = new TypeReference (parts [1], parts > [0], m_corlib); > + coreType = new TypeReference (parts [1], parts > [0], Corlib); > m_module.TypeReferences.Add (coreType); > } > if (!coreType.IsValueType) { > Index: ChangeLog > =================================================================== > --- ChangeLog (revision 66226) > +++ ChangeLog (working copy) > @@ -1,3 +1,11 @@ > +2006-10-05 Eyal Alaluf <[EMAIL PROTECTED]> > + > + Mono.Cecil/ReflectionReader.cs: > + Expose Corlib assembly refereice so SignatureReader can ise it. > + Mono.Cecil.Signatures/SignatureReader.cs: > + Added support for enums in custom attributes ctors, properties > and > + fields. > + > 2006-10-04 Eyal Alaluf <[EMAIL PROTECTED]> > > * Mono.Cecil/StructureReader.cs: > @@ -2,3 +10,2 @@ > Visit the module we load when a DLL has more then 1 module. > - Visit the module we load when a DLL has more then 1 > module. > Mono.Cecil/AssemblyNameReference.cs: > Index: Mono.Cecil.Signatures/SignatureReader.cs > =================================================================== > --- Mono.Cecil.Signatures/SignatureReader.cs (revision 66216) > +++ Mono.Cecil.Signatures/SignatureReader.cs (working copy) > @@ -587,7 +587,7 @@ > } > > CustomAttrib.FixedArg ReadFixedArg (byte [] data, BinaryReader > br, > - bool array, object param, ref bool read) > + bool array, TypeReference param, ref bool read) > { > CustomAttrib.FixedArg fa = new CustomAttrib.FixedArg (); > if (array) { > @@ -596,6 +596,7 @@ > > if (fa.NumElem == 0 || fa.NumElem == > 0xffffffff) { > fa.Elems = new CustomAttrib.Elem [0]; > + fa.NumElem = 0; > return fa; > } > > @@ -611,6 +612,95 @@ > return fa; > } > > + TypeReference CreateEnumTypeReference (string enumName) > + { > + string asmName = null; > + int asmStart = enumName.IndexOf (','); > + if (asmStart != -1) { > + asmName = enumName.Substring (asmStart + 1); > + enumName = enumName.Substring (0, asmStart); > + } > + // Inner class style is reflection style. > + enumName = enumName.Replace ('+', '/'); > + AssemblyNameReference asm = null; > + if (asmName == null) { > + // If no assembly is given then the ECMA > standard says the > + // assembly is either the current one or > mscorlib. > + if (m_reflectReader.Module.Types[enumName] != > null) > + return > m_reflectReader.Module.Types[enumName]; > + asm = m_reflectReader.Corlib; > + } > + else > + asm = AssemblyNameReference.Parse (asmName); > + > + string[] outers = enumName.Split ('/'); > + string outerfullname = outers[0]; > + string ns = null; > + int nsIndex = outerfullname.LastIndexOf ('.'); > + if (nsIndex != -1) > + ns = outerfullname.Substring(0, nsIndex); > + string name = outerfullname.Substring (nsIndex + 1); > + TypeReference decType = new TypeReference (name, ns, > asm); > + for (int i = 1; i < outers.Length; i++) > + { > + TypeReference t = new TypeReference (outers[i], > null, asm); > + t.DeclaringType = decType; > + decType = t; > + } > + decType.IsValueType = true; > + > + return decType; > + } > + > + TypeReference ReadTypeReference (byte[] data, BinaryReader br, > out ElementType elemType, out bool array) > + { > + array = false; > + elemType = (ElementType) br.ReadByte (); > + if (elemType == ElementType.SzArray) > + { > + elemType = (ElementType) br.ReadByte (); > + array = true; > + } > + > + switch (elemType) { > + case ElementType.Enum : > + return CreateEnumTypeReference (ReadUTF8String > (data, br)); > + case ElementType.Boxed : > + return m_reflectReader.SearchCoreType > (Constants.Object); > + case ElementType.String : > + return m_reflectReader.SearchCoreType > (Constants.String); > + case ElementType.Type : > + return m_reflectReader.SearchCoreType > (Constants.Type); > + case ElementType.Boolean : > + return m_reflectReader.SearchCoreType > (Constants.Boolean); > + case ElementType.Char : > + return m_reflectReader.SearchCoreType > (Constants.Char); > + case ElementType.R4 : > + return m_reflectReader.SearchCoreType > (Constants.Single); > + case ElementType.R8 : > + return m_reflectReader.SearchCoreType > (Constants.Double); > + case ElementType.I1 : > + return m_reflectReader.SearchCoreType > (Constants.SByte); > + case ElementType.I2 : > + return m_reflectReader.SearchCoreType > (Constants.Int16); > + case ElementType.I4 : > + return m_reflectReader.SearchCoreType > (Constants.Int32); > + case ElementType.I8 : > + return m_reflectReader.SearchCoreType > (Constants.Int64); > + case ElementType.U1 : > + return m_reflectReader.SearchCoreType > (Constants.Byte); > + case ElementType.U2 : > + return m_reflectReader.SearchCoreType > (Constants.UInt16); > + case ElementType.U4 : > + return m_reflectReader.SearchCoreType > (Constants.UInt32); > + case ElementType.U8 : > + return m_reflectReader.SearchCoreType > (Constants.UInt64); > + default : > + throw new MetadataFormatException ("Non valid > type in CustomAttrib.Elem: 0x{0}", > + ((byte) elemType).ToString("x2")); > + } > + } > + > internal CustomAttrib.NamedArg ReadNamedArg (byte [] data, > BinaryReader br, ref bool read) > { > CustomAttrib.NamedArg na = new CustomAttrib.NamedArg (); > @@ -625,42 +715,15 @@ > throw new MetadataFormatException ("Wrong kind > of namedarg found: 0x" + kind.ToString("x2")); > > bool array = false; > - na.FieldOrPropType = (ElementType) br.ReadByte (); > - if (na.FieldOrPropType == ElementType.SzArray) { > - na.FieldOrPropType = (ElementType) br.ReadByte > (); > - array = true; > - } > > - int next, length; > + TypeReference elemType = ReadTypeReference (data, br, > out na.FieldOrPropType, out array); > > - if (na.FieldOrPropType == ElementType.Enum) { > - read = false; > - return na; > - } > + na.FieldOrPropName = ReadUTF8String (data, br); > + na.FixedArg = ReadFixedArg (data, br, array, elemType, > ref read); > > - length = Utilities.ReadCompressedInteger (data, (int) > br.BaseStream.Position, out next); > - br.BaseStream.Position = next; > - > - // COMPACT FRAMEWORK NOTE: Encoding.GetString(byte[]) > is not supported. > - byte [] bytes = br.ReadBytes (length); > - na.FieldOrPropName = Encoding.UTF8.GetString (bytes, 0, > bytes.Length); > - > - na.FixedArg = ReadFixedArg (data, br, array, > na.FieldOrPropType, ref read); > - > return na; > } > > - // i hate this construction, should find something better > - CustomAttrib.Elem ReadElem (byte [] data, BinaryReader br, > object param, ref bool read) > - { > - if (param is TypeReference) > - return ReadElem (data, br, param as > TypeReference, ref read); > - else if (param is ElementType) > - return ReadElem (data, br, (ElementType) param, > ref read); > - else > - throw new MetadataFormatException ("Wrong > parameter for ReadElem: " + param.GetType ().FullName); > - } > - > CustomAttrib.Elem ReadElem (byte [] data, BinaryReader br, > TypeReference elemType, ref bool read) > { > CustomAttrib.Elem elem = new CustomAttrib.Elem (); > @@ -668,11 +731,20 @@ > string elemName = elemType.FullName; > > if (elemName == Constants.Object) { > - ElementType elementType = (ElementType) > br.ReadByte (); > - elem = ReadElem (data, br, elementType, ref > read); > + bool array; > + elemType = ReadTypeReference (data, br, out > elem.FieldOrPropType, out array); > + > + if (array) { > + read = false; // Don't know how to > represent arrays as an object value. > + return elem; > + } > + else if (elemType.FullName == Constants.Object) > + throw new MetadataFormatException ("Non > valid type in CustomAttrib.Elem after boxed prefix: 0x{0}", > + ((byte) > elem.FieldOrPropType).ToString("x2")); > + > + elem = ReadElem (data, br, elemType, ref read); > elem.String = elem.Simple = elem.Type = false; > elem.BoxedValueType = true; > - elem.FieldOrPropType = elementType; > return elem; > } > > @@ -694,19 +766,45 @@ > elem.Value = null; > br.BaseStream.Position++; > } else { > - int next, length = > Utilities.ReadCompressedInteger (data, (int) br.BaseStream.Position, out > next); > - br.BaseStream.Position = next; > - // COMPACT FRAMEWORK NOTE: > Encoding.GetString(byte[]) is not supported. > - byte [] bytes = br.ReadBytes (length); > - elem.Value = Encoding.UTF8.GetString > (bytes, 0, bytes.Length); > + elem.Value = ReadUTF8String (data, br); > } > - > return elem; > } > > elem.String = elem.Type = elem.BoxedValueType = false; > + if (!readSimpleValue (br, ref elem, elem.ElemType)) { > + TypeReference typeRef = GetEnumUnderlyingType > (elem.ElemType); > + if (typeRef == null || !readSimpleValue (br, > ref elem, typeRef)) > + read = false; > + } > > - switch (elemName) { > + return elem; > + } > + > + private IAssemblyResolver AssemblyResolver > + { > + get > + { > + return m_reflectReader.Module.Assembly.Resolver; > + } > + } > + > + private TypeReference GetEnumUnderlyingType (TypeReference > enumType) > + { > + TypeDefinition type = enumType as TypeDefinition; > + if (type == null && AssemblyResolver != null) > + { > + AssemblyDefinition asm = > AssemblyResolver.Resolve (enumType.Scope.Name); > + type = asm.MainModule.Types[enumType.FullName]; > + } > + if (type != null && type.IsEnum) > + return type.Fields.GetField > ("value__").FieldType; > + return null; > + } > + > + bool readSimpleValue (BinaryReader br, ref CustomAttrib.Elem > elem, TypeReference type) > + { > + switch (type.FullName) { > case Constants.Boolean : > elem.Value = br.ReadByte () == 1; > break; > @@ -744,120 +842,12 @@ > elem.Value = br.ReadUInt64 (); > break; > default : // enum > - read = false; > - return elem; > + return false; > } > - > elem.Simple = true; > - return elem; > + return true; > } > > - // elem in named args, only have an ElementType > - CustomAttrib.Elem ReadElem (byte [] data, BinaryReader br, > ElementType elemType, ref bool read) > - { > - CustomAttrib.Elem elem = new CustomAttrib.Elem (); > - > - if (elemType == ElementType.Boxed) { > - ElementType elementType = (ElementType) > br.ReadByte (); > - elem = ReadElem (data, br, elementType, ref > read); > - elem.String = elem.Simple = elem.Type = false; > - elem.BoxedValueType = true; > - elem.FieldOrPropType = elementType; > - return elem; > - } > - > - if (elemType == ElementType.Type || elemType == > ElementType.String) { // type or string > - switch (elemType) { > - case ElementType.String : > - elem.String = true; > - elem.BoxedValueType = elem.Simple = > elem.Type = false; > - elem.ElemType = > m_reflectReader.SearchCoreType (Constants.String); > - break; > - case ElementType.Type : > - elem.Type = true; > - elem.BoxedValueType = elem.Simple = > elem.String = false; > - elem.ElemType = > m_reflectReader.SearchCoreType (Constants.Type); > - break; > - } > - > - if (data [br.BaseStream.Position] == 0xff) { // > null > - elem.Value = null; > - br.BaseStream.Position++; > - } else { > - int next, length = > Utilities.ReadCompressedInteger (data, (int) br.BaseStream.Position, out > next); > - br.BaseStream.Position = next; > - // COMPACT FRAMEWORK NOTE: > Encoding.GetString(byte[]) is not supported. > - byte [] bytes = br.ReadBytes (length); > - elem.Value = Encoding.UTF8.GetString > (bytes, 0, bytes.Length); > - } > - > - return elem; > - } > - > - elem.String = elem.Type = elem.BoxedValueType = false; > - > - switch (elemType) { > - case ElementType.Boolean : > - elem.ElemType = m_reflectReader.SearchCoreType > (Constants.Boolean); > - elem.Value = br.ReadByte () == 1; > - break; > - case ElementType.Char : > - elem.ElemType = m_reflectReader.SearchCoreType > (Constants.Char); > - elem.Value = (char) br.ReadUInt16 (); > - break; > - case ElementType.R4 : > - elem.ElemType = m_reflectReader.SearchCoreType > (Constants.Single); > - elem.Value = br.ReadSingle (); > - break; > - case ElementType.R8 : > - elem.ElemType = m_reflectReader.SearchCoreType > (Constants.Double); > - elem.Value = br.ReadDouble (); > - break; > - case ElementType.I1 : > - elem.ElemType = m_reflectReader.SearchCoreType > (Constants.SByte); > - elem.Value = br.ReadSByte (); > - break; > - case ElementType.I2 : > - elem.ElemType = m_reflectReader.SearchCoreType > (Constants.Int16); > - elem.Value = br.ReadInt16 (); > - break; > - case ElementType.I4 : > - elem.ElemType = m_reflectReader.SearchCoreType > (Constants.Int32); > - elem.Value = br.ReadInt32 (); > - break; > - case ElementType.I8 : > - elem.ElemType = m_reflectReader.SearchCoreType > (Constants.Int64); > - elem.Value = br.ReadInt64 (); > - break; > - case ElementType.U1 : > - elem.ElemType = m_reflectReader.SearchCoreType > (Constants.Byte); > - elem.Value = br.ReadByte (); > - break; > - case ElementType.U2 : > - elem.ElemType = m_reflectReader.SearchCoreType > (Constants.UInt16); > - elem.Value = br.ReadUInt16 (); > - break; > - case ElementType.U4 : > - elem.ElemType = m_reflectReader.SearchCoreType > (Constants.UInt32); > - elem.Value = br.ReadUInt32 (); > - break; > - case ElementType.U8 : > - elem.ElemType = m_reflectReader.SearchCoreType > (Constants.UInt64); > - elem.Value = br.ReadUInt64 (); > - break; > - case ElementType.Enum : > - read = false; > - return elem; > - default : > - throw new MetadataFormatException ("Non valid > type in CustomAttrib.Elem: 0x{0}", > - ((byte) elemType).ToString("x2")); > - } > - > - read = true; > - elem.Simple = true; > - return elem; > - } > - > MarshalSig ReadMarshalSig (byte [] data) > { > int start; > @@ -905,14 +895,21 @@ > return ms; > } > > + static internal string ReadUTF8String (byte [] data, > BinaryReader br) > + { > + int start = (int)br.BaseStream.Position; > + string val = ReadUTF8String (data, start, out start); > + br.BaseStream.Position = start; > + return val; > + } > + > static internal string ReadUTF8String (byte [] data, int pos, > out int start) > { > int length = Utilities.ReadCompressedInteger (data, > pos, out start); > - byte [] str = new byte [length]; > - Buffer.BlockCopy (data, start, str, 0, length); > + pos = start; > start += length; > - // COMPACT FRAMEWORK NOTE: Encoding.GetString(byte[]) > is not supported. > - return Encoding.UTF8.GetString (str, 0, str.Length); > + // COMPACT FRAMEWORK NOTE: Encoding.GetString (byte[]) > is not supported. > + return Encoding.UTF8.GetString (data, pos, length); > } > } > } > > > ------------------------------------------------------------------------ > > _______________________________________________ > Mono-devel-list mailing list > Mono-devel-list@lists.ximian.com > http://lists.ximian.com/mailman/listinfo/mono-devel-list _______________________________________________ Mono-devel-list mailing list Mono-devel-list@lists.ximian.com http://lists.ximian.com/mailman/listinfo/mono-devel-list