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

Reply via email to