[ilasm] fix the metadata version for v4 assemblies
[mono.git] / mcs / class / PEAPI / Metadata.cs
index 0a7a9d7a3e5a26d79a59a15772a55b9a50fd84ec..a618fe9189e152a3c457419048083559e4dcb270 100644 (file)
@@ -2,6 +2,7 @@ using System;
 using System.IO;
 using System.Collections;
 using System.Text;
+using System.Reflection;
 
 namespace PEAPI {
 
@@ -28,7 +29,7 @@ namespace PEAPI {
        /// <summary>
        /// Attributes for this assembly
        /// </summary>
-       public enum AssemAttr { EnableJITCompileTracking = 0x8000, 
+       public enum AssemAttr { Retargetable = 0x100, EnableJITCompileTracking = 0x8000, 
                DisableJITCompileOptimizer = 0x4000}
 
        /// <summary>
@@ -46,6 +47,7 @@ namespace PEAPI {
        /// <summary>
        /// Attibutes for a class
        /// </summary>
+       [Flags]
        public enum TypeAttr {Private, Public, NestedPublic, NestedPrivate, 
                NestedFamily, NestedAssembly, NestedFamAndAssem, NestedFamOrAssem, 
                SequentialLayout, ExplicitLayout = 0x10, Interface = 0x20, 
@@ -70,7 +72,7 @@ namespace PEAPI {
                Family, FamOrAssem, Public, Static = 0x0010, PublicStatic = 0x16, 
                Final = 0x0020, PublicStaticFinal = 0x36, Virtual = 0x0040, 
                PrivateVirtual, PublicVirtual = 0x0046, HideBySig = 0x0080, 
-               NewSlot = 0x0100, Abstract = 0x0400, SpecialName = 0x0800,
+               NewSlot = 0x0100, Strict = 0x200, Abstract = 0x0400, SpecialName = 0x0800,
                RTSpecialName = 0x1000, SpecialRTSpecialName = 0x1800, 
                HasSecurity = 0x4000, RequireSecObject = 0x8000}
 
@@ -78,8 +80,11 @@ namespace PEAPI {
        /// Attributes for .pinvokeimpl method declarations
        /// </summary>
        public enum PInvokeAttr { nomangle = 1, ansi = 2, unicode = 4, autochar = 6,
+               bestfit_on = 0x0010, bestfit_off = 0x0020, bestfit_mask = 0x0030,
                lasterr = 0x0040, winapi = 0x0100, cdecl = 0x0200,
-               stdcall = 0x0300, thiscall = 0x0400, fastcall = 0x0500 }
+               stdcall = 0x0300, thiscall = 0x0400, fastcall = 0x0500,
+               charmaperror_on = 0x1000, charmaperror_off = 0x2000
+       }
 
        /// <summary>
        /// Implementation attributes for a method
@@ -117,7 +122,7 @@ namespace PEAPI {
                add_ovf_un, mul_ovf, mul_ovf_un, sub_ovf, sub_ovf_un, endfinally, 
                stind_i = 0xDF, conv_u, arglist = 0xFE00, ceq, cgt, cgt_un, clt, clt_un, 
                localloc = 0xFE0F, endfilter = 0xFE11, volatile_ = 0xFE13, tail_, 
-               cpblk = 0xFE17, initblk, rethrow = 0xFE1A, refanytype = 0xFE1D}
+               cpblk = 0xFE17, initblk, rethrow = 0xFE1A, refanytype = 0xFE1D, readonly_ = 0xFE1E }
 
        /// <summary>
        /// CIL instructions requiring an integer parameter
@@ -237,6 +242,8 @@ namespace PEAPI {
                protected bool done = false;
                protected MDTable tabIx;
                protected bool sortTable = false;
+               //Temporary hack.. 
+               private bool has_custom_attrs = false;
 
                internal MetaDataElement() { }
 
@@ -249,6 +256,11 @@ namespace PEAPI {
                        }
                }
 
+               public bool HasCustomAttr {
+                       get { return has_custom_attrs; }
+                       set { has_custom_attrs = value; }
+               }
+
                internal virtual uint GetCodedIx(CIx code) { return 0; }
 
                /// <summary>
@@ -459,9 +471,14 @@ namespace PEAPI {
 
                internal sealed override void BuildTables(MetaData md) 
                {
+                       md.AddToTable(MDTable.CustomAttribute, this);
+                       if (byteVal == null) {
+                               valIx = 0;
+                               return;
+                       }
+
                        BinaryWriter bw = new BinaryWriter(new MemoryStream());
                        bw.Write(byteVal);
-                       md.AddToTable(MDTable.CustomAttribute, this);
                        MemoryStream str = (MemoryStream)bw.BaseStream;
                        valIx = md.AddToBlobHeap(str.ToArray());
                }
@@ -485,19 +502,17 @@ namespace PEAPI {
        /// Descriptor for security permissions for a class or a method
        /// </summary>
 
-       public class DeclSecurity : MetaDataElement {
+       public abstract class BaseDeclSecurity : MetaDataElement {
 
                ushort action;
                MetaDataElement parent;
                uint permissionIx;
-               byte [] byteVal;
 
-               internal DeclSecurity(MetaDataElement paren, ushort act, byte [] val)        
+               internal BaseDeclSecurity(MetaDataElement paren, ushort act)
                {
                        parent = paren;
                        action = act;
                        tabIx = MDTable.DeclSecurity;
-                       byteVal = val;
                }
 
                internal override uint SortKey() 
@@ -514,15 +529,18 @@ namespace PEAPI {
                internal sealed override void BuildTables(MetaData md) 
                {
                        if (done) return;
+
                        BinaryWriter bw = new BinaryWriter (new MemoryStream ());
-                       bw.Write (byteVal);
                        md.AddToTable (MDTable.DeclSecurity, this);
                        MemoryStream str = (MemoryStream)bw.BaseStream;
+                       WriteSig (bw);
                        permissionIx = md.AddToBlobHeap(str.ToArray());
 
                        done = true;
                }
 
+               internal abstract void WriteSig (BinaryWriter bw);
+
                internal sealed override void Write(FileImage output) 
                {
                        output.Write(action);
@@ -532,6 +550,154 @@ namespace PEAPI {
 
        }
 
+       public class DeclSecurity : BaseDeclSecurity {
+
+               byte [] byteVal;
+
+               internal DeclSecurity(MetaDataElement paren, ushort act, byte [] val)        
+                       : base (paren, act)
+               {
+                       byteVal = val;
+               }
+
+               internal override void WriteSig (BinaryWriter bw)
+               {
+                       bw.Write (byteVal);
+               }
+
+       }
+
+       public class DeclSecurity_20 : BaseDeclSecurity {
+
+               PermissionSet ps;
+
+               internal DeclSecurity_20 (MetaDataElement paren, ushort act, PermissionSet ps)
+                       : base (paren, act)
+               {
+                        this.ps = ps;
+               }
+
+               internal override void WriteSig (BinaryWriter bw)
+               {
+                       ps.Write (bw);
+               }
+       }
+
+       public class PermissionMember {
+
+               MemberTypes member_type;
+               PEAPI.Type type;
+               string name;
+               object value;
+
+               public PermissionMember (MemberTypes member_type, PEAPI.Type type, string name, object value)
+               {
+                       this.member_type = member_type;
+                       this.type = type;
+                       this.name = name;
+                       this.value = value;
+               }
+
+               public void Write (BinaryWriter bw)
+               {
+                       byte [] b;
+
+                       if (member_type == MemberTypes.Field)
+                               bw.Write ((byte) 0x53);
+                       else
+                               //Property
+                               bw.Write ((byte) 0x54);
+
+                       if (type is PrimitiveType) {
+                               bw.Write (type.GetTypeIndex ());
+                       } else {
+                               //must be enum
+                               bw.Write ((byte) 0x55); //ENUM
+
+                               b = Encoding.UTF8.GetBytes (((ClassRef) type).TypeName ());
+                               MetaData.CompressNum ((uint) b.Length, (MemoryStream) bw.BaseStream);
+                               bw.Write (b);
+                       }
+                       
+                       b = Encoding.UTF8.GetBytes (name);
+                       MetaData.CompressNum ((uint) b.Length, (MemoryStream) bw.BaseStream);
+                       bw.Write (b);
+
+                       ((Constant) value).Write (bw);
+               }
+
+       }
+
+       public class Permission
+       {
+               PEAPI.Type type;
+
+               //PermissionMembers
+               ArrayList members;
+               string name;
+
+               public Permission (PEAPI.Type type, string name)
+               {
+                       this.type = type;
+                       this.name = name;
+               }
+
+               public void AddMember (PEAPI.PermissionMember member)
+               {
+                       if (members == null)
+                               members = new ArrayList ();
+
+                       members.Add (member);
+               }
+
+               public void Write (BinaryWriter bw)
+               {
+                       byte [] b = Encoding.UTF8.GetBytes (name);
+                       MetaData.CompressNum ((uint) b.Length, (MemoryStream) bw.BaseStream);
+                       bw.Write (b);
+
+                       BinaryWriter perm_writer = new BinaryWriter (new MemoryStream (), Encoding.Unicode);
+                       MemoryStream str = (MemoryStream) perm_writer.BaseStream;
+
+                       MetaData.CompressNum ((uint) members.Count, str);//number of params
+                       foreach (PermissionMember member in members)
+                               member.Write (perm_writer);
+
+                       bw.Write ((byte) str.Length); //(optional) parameters length
+                       bw.Write (str.ToArray ());
+               }
+       }
+
+       public class PermissionSet 
+       {
+               PEAPI.SecurityAction sec_action;
+               ArrayList permissions;
+               PEAPI.PermissionSet ps;
+
+               public PermissionSet (PEAPI.SecurityAction sec_action)
+               {
+                       this.sec_action = sec_action;
+               }
+
+               public void AddPermission (PEAPI.Permission perm)
+               {
+                       if (permissions == null)
+                               permissions = new ArrayList ();
+
+                       permissions.Add (perm);
+               }
+
+               public void Write (BinaryWriter bw)
+               {
+                       bw.Write ((byte) 0x2e);
+                       MetaData.CompressNum ((uint) permissions.Count, (MemoryStream) bw.BaseStream);
+
+                       foreach (Permission perm in permissions)
+                               perm.Write (bw);
+               }
+
+       }
+
        /**************************************************************************/  
        /// <summary>
        /// Descriptor for layout information for a field
@@ -821,6 +987,13 @@ namespace PEAPI {
                        output.StringsIndex (nameIx);
                }
 
+               internal sealed override uint GetCodedIx(CIx code) 
+               {
+                       switch (code) {
+                               case (CIx.HasCustomAttr) : return 19; 
+                       }
+                       return 0;
+               }
 
        }
 
@@ -1006,11 +1179,11 @@ namespace PEAPI {
                        nameIx = md.AddToStringsHeap(mrName);
                        if (resourceBytes != null) {
                                if (rRef != null)
-                                       throw new Exception("ERROR:  Manifest Resource has byte value and file reference");
+                                       throw new PEFileException ("Manifest Resource has byte value and file reference");
                                fileOffset = md.AddResource(resourceBytes);
                        } else {
                                if (rRef == null)
-                                       throw new Exception("ERROR:  Manifest Resource has no implementation or value");
+                                       throw new PEFileException ("Manifest Resource has no implementation or value");
                                rRef.BuildTables (md);
                        }
 
@@ -1167,6 +1340,10 @@ namespace PEAPI {
                        tabIx = MDTable.Param;
                }
 
+               public bool HasMarshalInfo {
+                       get { return marshalInfo != null; }
+               }
+
                /// <summary>
                /// Add a default value to this parameter
                /// </summary>
@@ -1527,9 +1704,14 @@ namespace PEAPI {
                /// <param name="pars">parameters</param>
                /// <returns>a descriptor for this new method</returns>
                public MethodDef AddMethod(string name, Type retType, Param[] pars) 
+               {
+                       return AddMethod (name, new Param (ParamAttr.Default, "", retType), pars);
+               }
+
+               public MethodDef AddMethod (string name, Param ret_param, Param [] pars) 
                {
                        // Console.WriteLine("Adding method " + name + " to class " + this.name);
-                       MethodDef meth = new MethodDef(metaData,name,retType, pars);
+                       MethodDef meth = new MethodDef(metaData,name, ret_param, pars);
                        methods.Add(meth);
                        return meth;
                }
@@ -1544,9 +1726,9 @@ namespace PEAPI {
                /// <param name="pars">parameters</param>
                /// <returns>a descriptor for this new method</returns>
                public MethodDef AddMethod(MethAttr mAtts, ImplAttr iAtts, string name, 
-                               Type retType, Param[] pars) {
+                               Param ret_param, Param [] pars) {
                        // Console.WriteLine("Adding method " + name + " to class " + this.name);
-                       MethodDef meth = new MethodDef(metaData,mAtts,iAtts,name,retType,pars);
+                       MethodDef meth = new MethodDef (metaData, mAtts, iAtts, name, ret_param, pars);
                        methods.Add(meth);
                        return meth;
                }
@@ -2019,7 +2201,7 @@ namespace PEAPI {
                internal sealed override void TypeSig(MemoryStream str) 
                {
                        if (index < 0)
-                               throw new Exception (String.Format ("Unresolved {0} - {1}", (GenParamType) GetTypeIndex (), param_name));
+                               throw new PEFileException (String.Format ("Unresolved {0} - {1}", (GenParamType) GetTypeIndex (), param_name));
                        str.WriteByte(typeIndex);
                        MetaData.CompressNum ((uint) index, str);
                }
@@ -2285,18 +2467,13 @@ namespace PEAPI {
                /// <param name="elementType">the type of the elements</param>
                /// <param name="dimensions">the number of dimensions</param>
                /// <param name="loBounds">lower bounds of dimensions</param>
-               /// <param name="upBounds">upper bounds of dimensions</param>
+               /// <param name="sizes">sizes for the dimensions</param>
                public BoundArray(Type elementType, uint dimensions, int[] loBounds, 
-                               int[] upBounds) : base (elementType,0x14) 
+                               int[] sizes) : base (elementType,0x14) 
                {
                        numDims = dimensions;
                        lowerBounds = loBounds;
-                       if (upBounds == null)
-                               return;
-                       sizes = new int[loBounds.Length];
-                       for (int i=0; i < loBounds.Length; i++) {
-                               sizes[i] = upBounds[i] - loBounds[i] + 1;
-                       }
+                       this.sizes = sizes;
                }
 
                /// <summary>
@@ -2340,11 +2517,54 @@ namespace PEAPI {
                        if ((lowerBounds != null) && (lowerBounds.Length > 0)) {
                                MetaData.CompressNum((uint)lowerBounds.Length,str);
                                for (int i=0; i < lowerBounds.Length; i++) {
-                                       MetaData.CompressNum((uint)lowerBounds[i],str);
+                                       CompressSignedNum (lowerBounds[i],str);
                                }
                        } else str.WriteByte(0);
                }
+               private void CompressSignedNum (int val, MemoryStream str)
+               {
+                       uint uval = (uint) val;
+                       byte sign = 0;
+                       if (val < 0) {
+                               val = -val;
+                               sign = 1;
+                       }
+
+                       /* Map the signed number to an unsigned number in two ways.
+
+                            fval: left-rotated 2's complement representation
+                            sval: map the signed number to unsigned as follows: 0 -> 0, -1 -> 1, 1 -> 2, -2 -> 3, 2 -> 4, ....
+                                  the mapping is: x -> 2*|x| - signbit(x)
+                       */
+                       uint fval = (uval << 1) | sign;
+                       int sval = (val  << 1) - sign;
+
+                       /* An overly clever transformation: 
+
+                          a. sval is used to determine the number of bytes in the compressed representation.
+                          b. fval is truncated to the appropriate number of bits and output using the 
+                             normal unsigned-int compressor.
 
+                          However, or certain values, the truncated fval doesn't carry enough information to round trip.
+
+                               (fval & 0x3FFF) <= 0x7F => compressor emits 1 byte, not 2 => there is aliasing of values
+
+                          So, we use full 4 bytes to encode such values.
+
+                          LAMESPEC: The Microsoft implementation doesn't appear to handle this subtle case.
+                                    e.g., it ends up encoding -8192 as the byte 0x01, which decodes to -64
+                       */
+                       if (sval <= 0x7F)
+                               MetaData.CompressNum (fval & 0x7F, str);
+                       else if (sval <= 0x3FFF && (fval & 0x3FFF) > 0x7F)
+                               MetaData.CompressNum (fval & 0x3FFF, str);
+                       else if (sval <= 0x1FFFFFFF && (fval & 0x1FFFFFFF) > 0x3FFF)
+                               MetaData.CompressNum (fval & 0x1FFFFFFF, str);
+                       else
+                               /* FIXME: number cannot be represented.  Report a warning.  */
+                               // throw new Exception ("cannot represent signed value" + -val);
+                               MetaData.CompressNum (fval, str);
+               }
        }
 
        #endregion
@@ -2462,7 +2682,7 @@ namespace PEAPI {
        /// <summary>
        /// Descriptor for THIS module
        /// </summary>
-       public class Module : ResolutionScope {
+       public class Module : ResolutionScope, IExternRef {
 
                Guid mvid;
                uint mvidIx = 0;
@@ -2478,6 +2698,21 @@ namespace PEAPI {
                        get { return mvid; }
                }
 
+               public ClassRef AddClass(string nsName, string name) 
+               {
+                       ClassRef aClass = new ClassRef (nsName, name, metaData);
+                       metaData.AddToTable (MDTable.TypeRef, aClass);
+                       aClass.SetParent (this);
+                       return aClass;
+               }
+
+               public ClassRef AddValueClass(string nsName, string name) 
+               {
+                       ClassRef aClass = AddClass (nsName, name);
+                       aClass.MakeValueClass (ValueClass.ValueType);
+                       return aClass;
+               }
+
                internal sealed override uint Size(MetaData md) 
                {
                        return 2 + md.StringsIndexSize() + 3 * md.GUIDIndexSize();
@@ -3586,7 +3821,6 @@ namespace PEAPI {
                // private static readonly byte LocalSigByte = 0x7;
                uint parIx = 0, textOffset = 0;
                private CallConv callConv = CallConv.Default;
-               private Type retType;
                private int gen_param_count;
 
                MetaData metaData;
@@ -3603,21 +3837,23 @@ namespace PEAPI {
                ImplMap pinvokeImpl;
                Param ret_param;
 
-
-               internal MethodDef(MetaData md, string name, Type retType, Param[] pars) : base (name)
+               internal MethodDef (MetaData md, string name, Param ret_param, Param [] pars)
+                       : this (md, 0, 0, name, ret_param, pars)
                {
-                       this.retType = retType;
-                       metaData = md;
-                       parList = pars;
-                       if (parList != null) numPars = parList.Length;
-                       tabIx = MDTable.Method;
                }
 
                internal MethodDef (MetaData md, MethAttr mAttrSet, ImplAttr iAttrSet, string name, 
-                               Type retType, Param [] pars) : this (md, name, retType, pars)
+                               Param ret_param, Param [] pars) 
+                       : base (name)
                {
                        methFlags = (ushort)mAttrSet;
                        implFlags = (ushort)iAttrSet;
+                       this.ret_param = ret_param;
+                       metaData = md;
+                       parList = pars;
+                       if (parList != null) 
+                               numPars = parList.Length;
+                       tabIx = MDTable.Method;
                }
 
                internal Param[] GetPars() 
@@ -3703,7 +3939,6 @@ namespace PEAPI {
                /* Add Marshal info for return type */
                public void AddRetTypeMarshallInfo (NativeType marshallType) 
                {
-                       ret_param = new Param (ParamAttr.HasFieldMarshal, "", retType);
                        ret_param.AddMarshallInfo (marshallType);
                }
 
@@ -3738,7 +3973,7 @@ namespace PEAPI {
                        for (int i=0; i < numPars; i++) {
                                pars[i] = parList[i].GetParType();
                        }
-                       varArgSig = new MethodRef(this,name,retType,pars,true,optPars, 0);
+                       varArgSig = new MethodRef (this, name, ret_param.GetParType (), pars, true, optPars, 0);
 
                        if (varArgSigList == null)
                                varArgSigList = new ArrayList ();
@@ -3752,9 +3987,9 @@ namespace PEAPI {
                        if ((callConv & CallConv.Generic) == CallConv.Generic)
                                MetaData.CompressNum ((uint) gen_param_count, sig);
                        MetaData.CompressNum((uint)numPars,sig);
-                       if (ret_param != null)
-                               ret_param.seqNo = 0;
-                       retType.TypeSig(sig);
+
+                       ret_param.seqNo = 0;
+                       ret_param.TypeSig (sig);
                        for (ushort i=0; i < numPars; i++) {
                                parList[i].seqNo = (ushort)(i+1);
                                parList[i].TypeSig(sig);
@@ -3783,7 +4018,7 @@ namespace PEAPI {
                        nameIx = md.AddToStringsHeap(name);
                        sigIx = GetSigIx(md);
                        parIx = md.TableIndex(MDTable.Param);
-                       if (ret_param != null) {
+                       if (ret_param.HasMarshalInfo || ret_param.HasCustomAttr) {
                                md.AddToTable(MDTable.Param, ret_param);
                                ret_param.BuildTables(md);
                        }
@@ -3967,6 +4202,8 @@ namespace PEAPI {
                public static readonly NativeType VariantBool = new NativeType(0x25);
                public static readonly NativeType FuncPtr = new NativeType(0x26);
                public static readonly NativeType AsAny = new NativeType(0x28);
+               public static readonly NativeType LPStruct = new NativeType(0x2b);
+               public static readonly NativeType Error = new NativeType(0x2d);
 
                protected byte typeIndex;
 
@@ -4308,6 +4545,11 @@ namespace PEAPI {
                        tabIx = MDTable.AssemblyRef;
                }
 
+               public void AddAssemblyAttr (AssemAttr aa)
+               {
+                       flags |= (uint)aa;
+               }
+
                /// <summary>
                /// Add version information about this external assembly
                /// </summary>
@@ -4692,7 +4934,9 @@ namespace PEAPI {
                private static readonly uint max3BitSmlIx = 0x1FFF;
                private static readonly uint max5BitSmlIx = 0x7FF;
                // NOTE: version and stream name strings MUST always be quad padded
-#if NET_2_0 || BOOTSTRAP_NET_2_0
+#if NET_4_0 || BOOTSTRAP_NET_4_0
+               private static readonly string version = "v4.0.30319\0\0";
+#elif NET_2_0 || BOOTSTRAP_NET_2_0
                private static readonly string version = "v2.0.50727\0\0";
 #else
                private static readonly string version = "v1.1.4322\0\0\0";
@@ -4882,7 +5126,7 @@ namespace PEAPI {
                        cattr_list.Add (cattr);
                }
 
-               internal void AddDeclSecurity (DeclSecurity decl_sec)
+               internal void AddDeclSecurity (BaseDeclSecurity decl_sec)
                {
                        if (declsec_list == null)
                                declsec_list = new ArrayList ();
@@ -4949,9 +5193,9 @@ namespace PEAPI {
 
                internal static void CompressNum(uint val, MemoryStream sig) 
                {
-                       if (val < 0x7F) {
+                       if (val <= 0x7F) {
                                sig.WriteByte((byte)val);
-                       } else if (val < 0x3FFF) {
+                       } else if (val <= 0x3FFF) {
                                byte b1 = (byte)((val >> 8) | 0x80);
                                byte b2 = (byte)(val & FileImage.iByteMask[0]);
                                sig.WriteByte(b1);
@@ -5169,7 +5413,7 @@ namespace PEAPI {
                        }
 
                        if (declsec_list != null) {
-                               foreach (DeclSecurity decl_sec in declsec_list)
+                               foreach (BaseDeclSecurity decl_sec in declsec_list)
                                        decl_sec.BuildTables (this);
                        }
 
@@ -5201,7 +5445,6 @@ namespace PEAPI {
                        // will _ALWAYS_ be in the correct order as embedded in BuildMDTables
 
                        SortTable(metaDataTables[(int)MDTable.Constant]);
-                       SortTable(metaDataTables[(int)MDTable.CustomAttribute]);
                        SortTable(metaDataTables[(int)MDTable.FieldMarshal]);
                        SortTable(metaDataTables[(int)MDTable.DeclSecurity]);
                        SortTable(metaDataTables[(int)MDTable.MethodSemantics]);
@@ -5217,6 +5460,7 @@ namespace PEAPI {
                        SortTable(metaDataTables[(int)MDTable.GenericParamConstraint]);
 #endif 
                        SortTable(metaDataTables[(int)MDTable.InterfaceImpl]);
+                       SortTable(metaDataTables[(int)MDTable.CustomAttribute]);
 
                }