Add all missing sequential layout directives to corlib and system.
[mono.git] / mcs / class / corlib / System.Reflection / AssemblyName.cs
index 42b32953736273ff92d03d6e24f8f374b9bbfd24..8e96227d2d292eda1c4e7a36b07fac64f2699cf3 100644 (file)
@@ -7,7 +7,7 @@
 //
 // (C) 2001 Ximian, Inc.  http://www.ximian.com
 // Portions (C) 2002 Motus Technologies Inc. (http://www.motus.com)
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
-using System;
 using System.Configuration.Assemblies;
 using System.Globalization;
-using System.Reflection;
 using System.Runtime.Serialization;
+using System.Security;
 using System.Security.Cryptography;
+using System.Security.Permissions;
 using System.Text;
 using System.Runtime.InteropServices;
 using System.Runtime.CompilerServices;
+using System.IO;
+
+using Mono.Security;
+using Mono.Security.Cryptography;
 
 namespace System.Reflection {
 
@@ -45,9 +49,15 @@ namespace System.Reflection {
 // a.  Uniform Resource Identifiers (URI): Generic Syntax
 //     http://www.ietf.org/rfc/rfc2396.txt
 
+       [ComVisible (true)]
+       [ComDefaultInterfaceAttribute (typeof (_AssemblyName))]
        [Serializable]
-       [MonoTODO ("Fix serialization compatibility with MS.NET")]
-       public sealed class AssemblyName  : ICloneable, ISerializable, IDeserializationCallback {
+       [ClassInterfaceAttribute (ClassInterfaceType.None)]
+       [StructLayout (LayoutKind.Sequential)]
+       public sealed class AssemblyName  : ICloneable, ISerializable, IDeserializationCallback, _AssemblyName {
+
+#pragma warning disable 169
+               #region Synch with object-internals.h
                string name;
                string codebase;
                int major, minor, build, revision;
@@ -59,6 +69,9 @@ namespace System.Reflection {
                byte[] keyToken;
                AssemblyVersionCompatibility versioncompat;
                Version version;
+               ProcessorArchitecture processor_architecture = ProcessorArchitecture.None;
+               #endregion
+#pragma warning restore 169            
                
                public AssemblyName ()
                {
@@ -66,12 +79,29 @@ namespace System.Reflection {
                        versioncompat = AssemblyVersionCompatibility.SameMachine;
                }
 
-#if NET_2_0
+               [MethodImpl (MethodImplOptions.InternalCall)]
+               static extern bool ParseName (AssemblyName aname, string assemblyName);
+               
                public AssemblyName (string assemblyName)
                {
-                       name = assemblyName;
+                       if (assemblyName == null)
+                               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.");
+               }
+               
+               [MonoLimitation ("Not used, as the values are too limited;  Mono supports more")]
+               public ProcessorArchitecture ProcessorArchitecture {
+                       get {
+                               return processor_architecture;
+                       }
+                       set {
+                               processor_architecture = value;
+                       }
                }
-#endif
 
                internal AssemblyName (SerializationInfo si, StreamingContext sc)
                {
@@ -79,7 +109,7 @@ namespace System.Reflection {
                        codebase = si.GetString ("_CodeBase");
                        version = (Version)si.GetValue ("_Version", typeof (Version));
                        publicKey = (byte[])si.GetValue ("_PublicKey", typeof (byte[]));
-                       keyToken = (byte[])si.GetValue ("_PublicToken", typeof (byte[]));
+                       keyToken = (byte[])si.GetValue ("_PublicKeyToken", typeof (byte[]));
                        hashalg = (AssemblyHashAlgorithm)si.GetValue ("_HashAlgorithm", typeof (AssemblyHashAlgorithm));
                        keypair = (StrongNameKeyPair)si.GetValue ("_StrongNameKeyPair", typeof (StrongNameKeyPair));
                        versioncompat = (AssemblyVersionCompatibility)si.GetValue ("_VersionCompatibility", typeof (AssemblyVersionCompatibility));
@@ -98,17 +128,12 @@ namespace System.Reflection {
                        set { codebase = value; }
                }
 
-               [MonoTODO("RFC 2396")]
-               private string Escape (string url) 
-               {
-                       // we already have code in mcs\class\System\System\Uri.cs
-                       // but Uri class ins't part of corlib !
-                       // TODO
-                       return url;
-               }
-
                public string EscapedCodeBase {
-                       get { return Escape (codebase); }
+                       get {
+                               if (codebase == null)
+                                       return null;
+                               return Uri.EscapeString (codebase, false, true, true);
+                       }
                }
 
                public CultureInfo CultureInfo {
@@ -124,10 +149,13 @@ namespace System.Reflection {
                public string FullName {
                        get {
                                if (name == null)
-                                       return null;
+                                       return string.Empty;
                                StringBuilder fname = new StringBuilder ();
-                               fname.Append (name);
-                               if (Version.ToString () != "0.0.0.0") {
+                               if (Char.IsWhiteSpace (name [0]))
+                                       fname.Append ("\"" + name + "\"");
+                               else
+                                       fname.Append (name);
+                               if (Version != null) {
                                        fname.Append (", Version=");
                                        fname.Append (Version.ToString ());
                                }
@@ -138,7 +166,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");
@@ -148,6 +176,10 @@ namespace System.Reflection {
                                                        fname.Append (pub_tok[i].ToString ("x2"));
                                        }
                                }
+
+                               if ((Flags & AssemblyNameFlags.Retargetable) != 0)
+                                       fname.Append (", Retargetable=Yes");
+
                                return fname.ToString ();
                        }
                }
@@ -164,27 +196,19 @@ namespace System.Reflection {
 
                public Version Version {
                        get {
-                               if (version != null) return version;
-                               
-                               if (name == null)
-                                       return null;
-                               if (build == -1)
-                                       version = new Version (major, minor);
-                               else
-                                       if (revision == -1)
-                                               version = new Version (major, minor, build);
-                               else
-                                       version = new Version (major, minor, build, revision);
-
                                return version;
                        }
 
                        set {
-                               major = value.Major;
-                               minor = value.Minor;
-                               build = value.Build;
-                               revision = value.Revision;
                                version = value;
+                               if (value == null)
+                                       major = minor = build = revision = 0;
+                               else {
+                                       major = value.Major;
+                                       minor = value.Minor;
+                                       build = value.Build;
+                                       revision = value.Revision;
+                               }
                        }
                }
 
@@ -199,46 +223,113 @@ namespace System.Reflection {
                        return (name != null) ? name : base.ToString ();
                }
 
-               public byte[] GetPublicKey() 
+               public byte[] GetPublicKey()
                {
-                       // to match MS implementation -- funny one
-                       if (publicKey != null)
-                               return publicKey;
-                       else if (name == null)
-                               return null;
-                       else
-                               return new byte [0];
+                       return publicKey;
                }
 
-               public byte[] GetPublicKeyToken() 
+               public byte[] GetPublicKeyToken ()
                {
                        if (keyToken != null)
                                return keyToken;
                        else 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 new byte [0];
+
+                               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) {
+                                               try {
+                                                       CryptoConvert.FromCapiPublicKeyBlob (
+                                                               publicKey, 12);
+                                                       return true;
+                                               } catch (CryptographicException) {
+                                               }
+                                       }
+                                       break;
+                               case 0x06: // public key
+                                       try {
+                                               CryptoConvert.FromCapiPublicKeyBlob (publicKey);
+                                               return true;
+                                       } catch (CryptographicException) {
+                                       }
+                                       break;
+                               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 new byte [0];
+
+                       if (!IsPublicKeyValid)
+                               throw new  SecurityException ("The public key is not valid.");
+
+                       return ComputePublicKeyToken ();
+               }
+
+               private byte [] ComputePublicKeyToken ()
+               {
+                       HashAlgorithm ha = SHA1.Create ();
+                       byte [] hash = ha.ComputeHash (publicKey);
+                       // we need the last 8 bytes in reverse order
+                       byte [] token = new byte [8];
+                       Array.Copy (hash, (hash.Length - 8), token, 0, 8);
+                       Array.Reverse (token, 0, 8);
+                       return token;
+               }
+
+               [MonoTODO]
+               public static bool ReferenceMatchesDefinition (AssemblyName reference, AssemblyName definition)
+               {
+                       if (reference == null)
+                               throw new ArgumentNullException ("reference");
+                       if (definition == null)
+                               throw new ArgumentNullException ("definition");
+                       if (reference.Name != definition.Name)
+                               return false;
+                       throw new NotImplementedException ();
+               }
+
                public void SetPublicKey (byte[] publicKey) 
                {
-                       flags = AssemblyNameFlags.PublicKey;
+                       if (publicKey == null)
+                               flags ^= AssemblyNameFlags.PublicKey;
+                       else
+                               flags |= AssemblyNameFlags.PublicKey;
                        this.publicKey = publicKey;
                }
 
@@ -247,11 +338,15 @@ namespace System.Reflection {
                        keyToken = publicKeyToken;
                }
 
+               [SecurityPermission (SecurityAction.Demand, SerializationFormatter = true)]
                public void GetObjectData (SerializationInfo info, StreamingContext context)
                {
+                       if (info == null)
+                               throw new ArgumentNullException ("info");
+
                        info.AddValue ("_Name", name);
                        info.AddValue ("_PublicKey", publicKey);
-                       info.AddValue ("_PublicToken", keyToken);
+                       info.AddValue ("_PublicKeyToken", keyToken);
                        info.AddValue ("_CultureInfo", cultureinfo != null ? cultureinfo.LCID : -1);
                        info.AddValue ("_CodeBase", codebase);
                        info.AddValue ("_Version", Version);
@@ -272,6 +367,7 @@ namespace System.Reflection {
                        an.minor = minor;
                        an.build = build;
                        an.revision = revision;
+                       an.version = version;
                        an.cultureinfo = cultureinfo;
                        an.flags = flags;
                        an.hashalg = hashalg;
@@ -293,8 +389,29 @@ namespace System.Reflection {
                                throw new ArgumentNullException ("assemblyFile");
 
                        AssemblyName aname = new AssemblyName ();
-                       Assembly.InternalGetAssemblyName (System.IO.Path.GetFullPath (assemblyFile), aname);
+                       Assembly.InternalGetAssemblyName (Path.GetFullPath (assemblyFile), aname);
                        return aname;
                }
+
+               void _AssemblyName.GetIDsOfNames ([In] ref Guid riid, IntPtr rgszNames, uint cNames, uint lcid, IntPtr rgDispId)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               void _AssemblyName.GetTypeInfo (uint iTInfo, uint lcid, IntPtr ppTInfo)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               void _AssemblyName.GetTypeInfoCount (out uint pcTInfo)
+               {
+                       throw new NotImplementedException ();
+               }
+
+               void _AssemblyName.Invoke (uint dispIdMember, [In] ref Guid riid, uint lcid, short wFlags, IntPtr pDispParams,
+                       IntPtr pVarResult, IntPtr pExcepInfo, IntPtr puArgErr)
+               {
+                       throw new NotImplementedException ();
+               }
        }
 }