Merge pull request #900 from Blewzman/FixAggregateExceptionGetBaseException
[mono.git] / mcs / class / corlib / System.Reflection / AssemblyName.cs
index 128adc205bb3420146b0b5919774185ebc5e4477..c1114225767e564c7cb97f2774dbb07ca3e6f485 100644 (file)
@@ -32,6 +32,7 @@
 using System.Configuration.Assemblies;
 using System.Globalization;
 using System.Runtime.Serialization;
+using System.Security;
 using System.Security.Cryptography;
 using System.Security.Permissions;
 using System.Text;
@@ -40,6 +41,7 @@ using System.Runtime.CompilerServices;
 using System.IO;
 
 using Mono.Security;
+using Mono.Security.Cryptography;
 
 namespace System.Reflection {
 
@@ -47,15 +49,17 @@ namespace System.Reflection {
 // a.  Uniform Resource Identifiers (URI): Generic Syntax
 //     http://www.ietf.org/rfc/rfc2396.txt
 
-#if NET_2_0
        [ComVisible (true)]
        [ComDefaultInterfaceAttribute (typeof (_AssemblyName))]
-#endif
        [Serializable]
        [ClassInterfaceAttribute (ClassInterfaceType.None)]
-       [MonoTODO ("Fix serialization compatibility with MS.NET")]
+       [StructLayout (LayoutKind.Sequential)]
+#if MOBILE
+       public sealed class AssemblyName  : ICloneable, ISerializable, IDeserializationCallback {
+#else
        public sealed class AssemblyName  : ICloneable, ISerializable, IDeserializationCallback, _AssemblyName {
-
+#endif
+#pragma warning disable 169
                #region Synch with object-internals.h
                string name;
                string codebase;
@@ -68,20 +72,19 @@ namespace System.Reflection {
                byte[] keyToken;
                AssemblyVersionCompatibility versioncompat;
                Version version;
-#if NET_2_0
-               ProcessorArchitecture processor_architecture;
-#else
-               int processor_architecture;
-#endif
-        #endregion
-               
+               ProcessorArchitecture processor_architecture = ProcessorArchitecture.None;
+               #endregion
+#pragma warning restore 169            
+
+#if NET_4_5
+               AssemblyContentType contentType;
+#endif         
                public AssemblyName ()
                {
                        // defaults
                        versioncompat = AssemblyVersionCompatibility.SameMachine;
                }
 
-#if NET_2_0 || BOOTSTRAP_NET_2_0
                [MethodImpl (MethodImplOptions.InternalCall)]
                static extern bool ParseName (AssemblyName aname, string assemblyName);
                
@@ -91,14 +94,12 @@ namespace System.Reflection {
                                throw new ArgumentNullException ("assemblyName");
                        if (assemblyName.Length < 1)
                                throw new ArgumentException ("assemblyName cannot have zero length.");
-                       
+                               
                        if (!ParseName (this, assemblyName))
                                throw new FileLoadException ("The assembly name is invalid.");
                }
-#endif
                
-#if NET_2_0
-               [MonoTODO]
+               [MonoLimitation ("Not used, as the values are too limited;  Mono supports more")]
                public ProcessorArchitecture ProcessorArchitecture {
                        get {
                                return processor_architecture;
@@ -107,7 +108,6 @@ namespace System.Reflection {
                                processor_architecture = value;
                        }
                }
-#endif
 
                internal AssemblyName (SerializationInfo si, StreamingContext sc)
                {
@@ -155,9 +155,12 @@ namespace System.Reflection {
                public string FullName {
                        get {
                                if (name == null)
-                                       return null;
+                                       return string.Empty;
                                StringBuilder fname = new StringBuilder ();
-                               fname.Append (name);
+                               if (Char.IsWhiteSpace (name [0]))
+                                       fname.Append ("\"" + name + "\"");
+                               else
+                                       fname.Append (name);
                                if (Version != null) {
                                        fname.Append (", Version=");
                                        fname.Append (Version.ToString ());
@@ -169,7 +172,7 @@ namespace System.Reflection {
                                        else
                                                fname.Append (cultureinfo.Name);
                                }
-                               byte[] pub_tok = GetPublicKeyToken ();
+                               byte [] pub_tok = InternalGetPublicKeyToken ();
                                if (pub_tok != null) {
                                        if (pub_tok.Length == 0)
                                                fname.Append (", PublicKeyToken=null");
@@ -179,6 +182,10 @@ namespace System.Reflection {
                                                        fname.Append (pub_tok[i].ToString ("x2"));
                                        }
                                }
+
+                               if ((Flags & AssemblyNameFlags.Retargetable) != 0)
+                                       fname.Append (", Retargetable=Yes");
+
                                return fname.ToString ();
                        }
                }
@@ -222,42 +229,121 @@ namespace System.Reflection {
                        return (name != null) ? name : base.ToString ();
                }
 
-               public byte[] GetPublicKey() 
+               public byte[] GetPublicKey()
                {
                        return publicKey;
-                       // FIXME: In some cases MS implementation returns 
-                       // "new byte [0]" instead of null
                }
 
-               public byte[] GetPublicKeyToken() 
+               public byte[] GetPublicKeyToken ()
                {
                        if (keyToken != null)
                                return keyToken;
-                       else if (publicKey == null)
+                       if (publicKey == null)
                                return null;
-                       else {
-                               HashAlgorithm ha = null;
-                               switch (hashalg) {
-                                       case AssemblyHashAlgorithm.MD5:
-                                               ha = MD5.Create ();
-                                               break;
-                                       default:
-                                               // None default to SHA1
-                                               ha = SHA1.Create ();
-                                               break;
-                               }
-                               byte[] hash = ha.ComputeHash (publicKey);
-                               // we need the last 8 bytes in reverse order
-                               keyToken = new byte [8];
-                               Array.Copy (hash, (hash.Length - 8), keyToken, 0, 8);
-                               Array.Reverse (keyToken, 0, 8);
+
+                               if (publicKey.Length == 0)
+                                       return EmptyArray<byte>.Value;
+
+                               if (!IsPublicKeyValid)
+                                       throw new  SecurityException ("The public key is not valid.");
+
+                               keyToken = ComputePublicKeyToken ();
                                return keyToken;
+               }
+
+               private bool IsPublicKeyValid {
+                       get {
+                               // check for ECMA key
+                               if (publicKey.Length == 16) {
+                                       int i = 0;
+                                       int sum = 0;
+                                       while (i < publicKey.Length)
+                                               sum += publicKey [i++];
+                                       if (sum == 4)
+                                               return true;
+                               }
+
+                               switch (publicKey [0]) {
+                               case 0x00: // public key inside a header
+                                       if (publicKey.Length > 12 && publicKey [12] == 0x06) {
+#if MOBILE
+                                               return true;
+#else
+                                               try {
+                                                       CryptoConvert.FromCapiPublicKeyBlob (
+                                                               publicKey, 12);
+                                                       return true;
+                                               } catch (CryptographicException) {
+                                               }
+#endif
+                                       }
+                                       break;
+                               case 0x06: // public key
+#if MOBILE
+                                       return true;
+#else
+                                       try {
+                                               CryptoConvert.FromCapiPublicKeyBlob (publicKey);
+                                               return true;
+                                       } catch (CryptographicException) {
+                                       }
+                                       break;                                  
+#endif
+                               case 0x07: // private key
+                                       break;
+                               }
+
+                               return false;
                        }
                }
 
+               private byte [] InternalGetPublicKeyToken ()
+               {
+                       if (keyToken != null)
+                               return keyToken;
+
+                       if (publicKey == null)
+                               return null;
+
+                       if (publicKey.Length == 0)
+                               return EmptyArray<byte>.Value;
+
+                       if (!IsPublicKeyValid)
+                               throw new  SecurityException ("The public key is not valid.");
+
+                       return ComputePublicKeyToken ();
+               }
+
+               [MethodImplAttribute (MethodImplOptions.InternalCall)]
+               extern unsafe static void get_public_token (byte* token, byte* pubkey, int len);
+
+               private unsafe byte [] ComputePublicKeyToken ()
+               {
+                       byte [] token = new byte [8];
+                       fixed (byte* pkt = token)
+                       fixed (byte *pk = publicKey)
+                               get_public_token (pkt, pk, publicKey.Length);
+                       return token;
+               }
+
+               public static bool ReferenceMatchesDefinition (AssemblyName reference, AssemblyName definition)
+               {
+                       if (reference == null)
+                               throw new ArgumentNullException ("reference");
+                       if (definition == null)
+                               throw new ArgumentNullException ("definition");
+                       
+                       // we only compare the simple assembly name to be consistent with MS .NET,
+                       // which is the result of a bug in their implementation (see https://connect.microsoft.com/VisualStudio/feedback/details/752902)
+                       return string.Equals (reference.Name, definition.Name, StringComparison.OrdinalIgnoreCase);
+               }
+
                public void SetPublicKey (byte[] publicKey) 
                {
-                       flags = AssemblyNameFlags.PublicKey;
+                       if (publicKey == null)
+                               flags ^= AssemblyNameFlags.PublicKey;
+                       else
+                               flags |= AssemblyNameFlags.PublicKey;
                        this.publicKey = publicKey;
                }
 
@@ -303,6 +389,7 @@ namespace System.Reflection {
                        an.publicKey = publicKey;
                        an.keyToken = keyToken;
                        an.versioncompat = versioncompat;
+                       an.processor_architecture = processor_architecture;
                        return an;
                }
 
@@ -317,11 +404,11 @@ namespace System.Reflection {
                                throw new ArgumentNullException ("assemblyFile");
 
                        AssemblyName aname = new AssemblyName ();
-                       Assembly.InternalGetAssemblyName (assemblyFile, aname);
+                       Assembly.InternalGetAssemblyName (Path.GetFullPath (assemblyFile), aname);
                        return aname;
                }
 
-#if NET_1_1
+#if !MOBILE
                void _AssemblyName.GetIDsOfNames ([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
                {
                        throw new NotImplementedException ();
@@ -343,5 +430,27 @@ namespace System.Reflection {
                        throw new NotImplementedException ();
                }
 #endif
+
+#if NET_4_5
+               public string CultureName {
+                       get {
+                               if (cultureinfo == null)
+                                       return null;
+                               if (cultureinfo.LCID == CultureInfo.InvariantCulture.LCID)
+                                       return "neutral";
+                               return cultureinfo.Name;
+                       }
+               }
+
+               [ComVisibleAttribute(false)]
+               public AssemblyContentType ContentType {
+                       get {
+                               return contentType;
+                       }
+                       set {
+                               contentType = value;
+                       }
+               }
+#endif
        }
 }