[Mono-dev] Parch for Enum support in Custom attributes

Jb Evain mono at evain.net
Mon Oct 9 09:03:26 EDT 2006


Hi Eyal,

The patch looks mostly good. Please use the new interface 
IRequireResolving I've just commited for the changes in CustomAttribute.

Please also follow the coding guideline used in Cecil.

I would also prefer a patch using a parameter instead of the 
ForceResolving property.

Also please send me the patch once it's done instead of commiting, I 
have to check that everything works fine on the writing part.

Thanks a lot,

Jb

Eyal Alaluf wrote:
> Hi, JB.
> 
> I worked a bit further on the patch and implemented the ForceRead logic
> for custom attributes.
> I aded a ForceResolving property to SignatureReader (it was the easiest way
> with the previous patch I made). If the patch if acceptable I'll prepare a
> separate and smaller patch to simplify SignatureReader abit and remove this
> property (pass it as a parameter).
> Attached is the patch and slightly modified test case.
> 
> Eyal.
> 
> On Thu, 5 Oct 2006, Jb Evain wrote:
> 
>> Date: Thu, 05 Oct 2006 19:16:47 +0200
>> From: Jb Evain <mono at evain.net>
>> To: Eyal Alaluf <eyala at mainsoft.com>
>> Cc: mono-devel-list at lists.ximian.com
>> Subject: Re: [Mono-dev] Parch for Enum support in Custom attributes
>>
>> 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  <eyala at mainsoft.com>
>>> +
>>> +    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  <eyala at mainsoft.com>
>>>       * 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 at lists.ximian.com
>>> http://lists.ximian.com/mailman/listinfo/mono-devel-list
>>
> 
> ------------------------------------------------------------------------
> 
> Index: Mono.Cecil/CustomAttribute.cs
> 
> ===================================================================
> 
> --- Mono.Cecil/CustomAttribute.cs	(revision 66447)
> 
> +++ Mono.Cecil/CustomAttribute.cs	(working copy)
> 
> @@ -102,6 +102,19 @@
> 
>  			set { m_blob = value; }
>  		}
>  
> +		public bool ForceRead ()
> +		{
> +			if (IsReadable)
> +				return true;
> +
> +			ReflectionReader r = m_ctor.DeclaringType.Module.Controller.Reader;
> +			CustomAttribute newCa = r.GetCustomAttribute (m_ctor, Blob, true);
> +			if (!newCa.IsReadable)
> +				return false;
> +			newCa.CopyTo (this);
> +			return true;
> +		}
> +
>  		public CustomAttribute (MethodReference ctor)
>  		{
>  			m_ctor = ctor;
> @@ -135,6 +148,7 @@
> 
>  
>  		static void Clone (IDictionary original, IDictionary target)
>  		{
> +			target.Clear ();
>  			foreach (DictionaryEntry entry in original)
>  				target.Add (entry.Key, entry.Value);
>  		}
> @@ -142,19 +156,24 @@
> 
>  		internal static CustomAttribute Clone (CustomAttribute custattr, ImportContext context)
>  		{
>  			CustomAttribute ca = new CustomAttribute (context.Import (custattr.Constructor));
> -			if (!custattr.IsReadable) {
> -				ca.IsReadable = false;
> -				ca.Blob = custattr.Blob;
> -				return ca;
> +			custattr.CopyTo(ca);
> +			return ca;
> +		}
> +
> +		private void CopyTo (CustomAttribute target)
> +		{
> +			target.IsReadable = IsReadable;
> +			if (!IsReadable) {
> +				target.Blob = Blob;
> +				return;
>  			}
>  
> -			foreach (object o in custattr.ConstructorParameters)
> -				ca.ConstructorParameters.Add (o);
> -			Clone (custattr.Fields, ca.Fields);
> -			Clone (custattr.FieldTypes, ca.FieldTypes);
> -			Clone (custattr.Properties, ca.Properties);
> -			Clone (custattr.PropertyTypes, ca.PropertyTypes);
> -			return ca;
> +			foreach (object o in ConstructorParameters)
> +				target.ConstructorParameters.Add (o);
> +			Clone (Fields, target.Fields);
> +			Clone (FieldTypes, target.FieldTypes);
> +			Clone (Properties, target.Properties);
> +			Clone (PropertyTypes, target.PropertyTypes);
>  		}
>  
>  		public void Accept (IReflectionVisitor visitor)
> Index: Mono.Cecil/ReflectionReader.cs
> 
> ===================================================================
> 
> --- Mono.Cecil/ReflectionReader.cs	(revision 66447)
> 
> +++ 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) {
> @@ -355,12 +364,20 @@
> 
>  			}
>  		}
>  
> -		public CustomAttribute GetCustomAttribute (MethodReference ctor, byte [] data)
> +		public CustomAttribute GetCustomAttribute (MethodReference ctor, byte [] data, bool forceResolving)
>  		{
> +			bool keepForceResolving = m_sigReader.ForceResolving;
> +			m_sigReader.ForceResolving = forceResolving;
>  			CustomAttrib sig = m_sigReader.GetCustomAttrib (data, ctor);
> +			m_sigReader.ForceResolving = keepForceResolving;
>  			return BuildCustomAttribute (ctor, sig);
>  		}
>  
> +		public CustomAttribute GetCustomAttribute (MethodReference ctor, byte [] data)
> +		{
> +			return GetCustomAttribute (ctor, data, false);
> +		}
> +
>  		public override void VisitModuleDefinition (ModuleDefinition mod)
>  		{
>  			VisitTypeDefinitionCollection (mod.Types);
> Index: ChangeLog
> 
> ===================================================================
> 
> --- ChangeLog	(revision 66447)
> 
> +++ ChangeLog	(working copy)
> 
> @@ -1,3 +1,17 @@
> 
> +2006-10-09  Eyal Alaluf  <eyala at mainsoft.com>
> +
> +	Mono.Cecil.Signatures/SignatureReader.cs:
> +		Added support for enums in custom attributes ctors, properties and
> +		fields.
> +	Mono.Cecil/CustomAttribute.cs:
> +		Add support for rereading custom attributes that contain references
> +		to enum in other assemblies.
> +	Mono.Cecil/ReflectionReader.cs:
> +		Add support for reading custom attributes while resolving enums from
> +		other assemblies then the current one.
> +	Mono.Cecil/ReflectionReader.cs:
> +		Expose Corlib assembly refereice so SignatureReader can ise it.
> +		
>  2006-10-09  Jb Evain  <jbevain at gmail.com>
>  
>  	* Mono.Cecil/SecurityDeclarationReader.cs:
> @@ -8,7 +22,6 @@
> 
>  
>  	* Mono.Cecil/StructureReader.cs:
>  		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:
>  	  	Allow "PublicToken=null" when parsing an assembly full name.
>  
> Index: Mono.Cecil.Signatures/SignatureReader.cs
> 
> ===================================================================
> 
> --- Mono.Cecil.Signatures/SignatureReader.cs	(revision 66447)
> 
> +++ Mono.Cecil.Signatures/SignatureReader.cs	(working copy)
> 
> @@ -41,6 +41,7 @@
> 
>  		MetadataRoot m_root;
>  		ReflectionReader m_reflectReader;
>  		byte [] m_blobData;
> +		bool m_forceResolving = false;
>  
>  		IDictionary m_signatures;
>  
> @@ -54,6 +55,12 @@
> 
>  			m_signatures = new Hashtable ();
>  		}
>  
> +		public bool ForceResolving
> +		{
> +			get { return m_forceResolving; }
> +			set { m_forceResolving = value; }
> +		}
> +
>  		public FieldSig GetFieldSig (uint index)
>  		{
>  			FieldSig f = m_signatures [index] as FieldSig;
> @@ -587,7 +594,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 +603,7 @@
> 
>  
>  				if (fa.NumElem == 0 || fa.NumElem == 0xffffffff) {
>  					fa.Elems = new CustomAttrib.Elem [0];
> +					fa.NumElem = 0;
>  					return fa;
>  				}
>  
> @@ -611,6 +619,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 +722,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 +738,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 +773,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 && ForceResolving && 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 +849,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 +902,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 at lists.ximian.com
> http://lists.ximian.com/mailman/listinfo/mono-devel-list



More information about the Mono-devel-list mailing list