1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.IO;
6 using System.Reflection;
7 using System.Runtime.ExceptionServices;
8 using System.Text;
9 
10 namespace System
11 {
12     [Serializable]
13     public sealed class ApplicationId
14     {
15         private readonly byte[] _publicKeyToken;
16 
ApplicationId(byte[] publicKeyToken, string name, Version version, string processorArchitecture, string culture)17         public ApplicationId(byte[] publicKeyToken, string name, Version version, string processorArchitecture, string culture)
18         {
19             if (name == null) throw new ArgumentNullException(nameof(name));
20             if (name.Length == 0) throw new ArgumentException(SR.Argument_EmptyApplicationName);
21             if (version == null) throw new ArgumentNullException(nameof(version));
22             if (publicKeyToken == null) throw new ArgumentNullException(nameof(publicKeyToken));
23 
24             _publicKeyToken = (byte[])publicKeyToken.Clone();
25             Name = name;
26             Version = version;
27             ProcessorArchitecture = processorArchitecture;
28             Culture = culture;
29         }
30 
31         public string Culture { get; }
32 
33         public string Name { get; }
34 
35         public string ProcessorArchitecture { get; }
36 
37         public Version Version { get; }
38 
39         public byte[] PublicKeyToken => (byte[])_publicKeyToken.Clone();
40 
Copy()41         public ApplicationId Copy() => new ApplicationId(_publicKeyToken, Name, Version, ProcessorArchitecture, Culture);
42 
ToString()43         public override string ToString ()
44         {
45             StringBuilder sb = StringBuilderCache.Acquire();
46             sb.Append(Name);
47             if (Culture != null)
48             {
49                 sb.Append(", culture=\"");
50                 sb.Append(Culture);
51                 sb.Append('"');
52             }
53             sb.Append(", version=\"");
54             sb.Append(Version.ToString());
55             sb.Append('"');
56             if (_publicKeyToken != null)
57             {
58                 sb.Append(", publicKeyToken=\"");
59                 sb.Append(EncodeHexString(_publicKeyToken));
60                 sb.Append('"');
61             }
62             if (ProcessorArchitecture != null)
63             {
64                 sb.Append(", processorArchitecture =\"");
65                 sb.Append(ProcessorArchitecture);
66                 sb.Append('"');
67             }
68             return StringBuilderCache.GetStringAndRelease(sb);
69         }
70 
HexDigit(int num)71         private static char HexDigit(int num) =>
72             (char)((num < 10) ? (num + '0') : (num + ('A' - 10)));
73 
EncodeHexString(byte[] sArray)74         private static string EncodeHexString(byte[] sArray)
75         {
76             string result = null;
77 
78             if (sArray != null)
79             {
80                 char[] hexOrder = new char[sArray.Length * 2];
81 
82                 int digit;
83                 for(int i = 0, j = 0; i < sArray.Length; i++) {
84                     digit = (int)((sArray[i] & 0xf0) >> 4);
85                     hexOrder[j++] = HexDigit(digit);
86                     digit = (int)(sArray[i] & 0x0f);
87                     hexOrder[j++] = HexDigit(digit);
88                 }
89                 result = new string(hexOrder);
90             }
91             return result;
92         }
93 
Equals(object o)94         public override bool Equals (object o)
95         {
96             ApplicationId other = (o as ApplicationId);
97             if (other == null)
98                 return false;
99 
100             if (!(Equals(Name, other.Name) &&
101                   Equals(Version, other.Version) &&
102                   Equals(ProcessorArchitecture, other.ProcessorArchitecture) &&
103                   Equals(Culture, other.Culture)))
104                 return false;
105 
106             if (_publicKeyToken.Length != other._publicKeyToken.Length)
107                 return false;
108 
109             for (int i = 0; i < _publicKeyToken.Length; i++)
110             {
111                 if (_publicKeyToken[i] != other._publicKeyToken[i])
112                     return false;
113             }
114 
115             return true;
116         }
117 
GetHashCode()118         public override int GetHashCode()
119         {
120             // Note: purposely skipping publicKeyToken, processor architecture and culture as they
121             // are less likely to make things not equal than name and version.
122             return Name.GetHashCode() ^ Version.GetHashCode();
123         }
124     }
125 }
126