Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Xml / System / Xml / XmlQualifiedName.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="XmlQualifiedName.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
7
8 namespace System.Xml {
9     using System.Collections;
10     using System.Diagnostics;
11 #if !SILVERLIGHT
12     using Microsoft.Win32;
13     using System.Reflection;
14     using System.Security;
15     using System.Security.Permissions;
16 #endif
17
18     /// <include file='doc\XmlQualifiedName.uex' path='docs/doc[@for="XmlQualifiedName"]/*' />
19     /// <devdoc>
20     ///    <para>[To be supplied.]</para>
21     /// </devdoc>
22 #if !SILVERLIGHT
23     [Serializable]
24 #endif
25     public class XmlQualifiedName {
26 #if !SILVERLIGHT
27         delegate int HashCodeOfStringDelegate(string s, int sLen, long additionalEntropy);
28         static HashCodeOfStringDelegate hashCodeDelegate = null;
29 #endif
30         string name;
31         string ns;
32
33 #if !SILVERLIGHT
34         [NonSerialized]
35 #endif
36         Int32  hash;
37
38         /// <include file='doc\XmlQualifiedName.uex' path='docs/doc[@for="XmlQualifiedName.Empty"]/*' />
39         /// <devdoc>
40         ///    <para>[To be supplied.]</para>
41         /// </devdoc>
42         public static readonly XmlQualifiedName Empty = new XmlQualifiedName(string.Empty);
43
44         /// <include file='doc\XmlQualifiedName.uex' path='docs/doc[@for="XmlQualifiedName.XmlQualifiedName"]/*' />
45         /// <devdoc>
46         ///    <para>[To be supplied.]</para>
47         /// </devdoc>
48         public XmlQualifiedName() : this(string.Empty, string.Empty) {}
49
50         /// <include file='doc\XmlQualifiedName.uex' path='docs/doc[@for="XmlQualifiedName.XmlQualifiedName1"]/*' />
51         /// <devdoc>
52         ///    <para>[To be supplied.]</para>
53         /// </devdoc>
54         public XmlQualifiedName(string name) : this(name, string.Empty) {}
55
56         /// <include file='doc\XmlQualifiedName.uex' path='docs/doc[@for="XmlQualifiedName.XmlQualifiedName2"]/*' />
57         /// <devdoc>
58         ///    <para>[To be supplied.]</para>
59         /// </devdoc>
60         public XmlQualifiedName(string name, string ns) {
61             this.ns   = ns   == null ? string.Empty : ns;
62             this.name = name == null ? string.Empty : name;
63         }
64
65         /// <include file='doc\XmlQualifiedName.uex' path='docs/doc[@for="XmlQualifiedName.Namespace"]/*' />
66         /// <devdoc>
67         ///    <para>[To be supplied.]</para>
68         /// </devdoc>
69         public string Namespace {
70             get { return ns; }
71         }
72
73         /// <include file='doc\XmlQualifiedName.uex' path='docs/doc[@for="XmlQualifiedName.Name"]/*' />
74         /// <devdoc>
75         ///    <para>[To be supplied.]</para>
76         /// </devdoc>
77         public string Name {
78             get { return name; }
79         }
80
81         /// <include file='doc\XmlQualifiedName.uex' path='docs/doc[@for="XmlQualifiedName.GetHashCode"]/*' />
82         /// <devdoc>
83         ///    <para>[To be supplied.]</para>
84         /// </devdoc>
85         public override int GetHashCode() {
86             if(hash == 0) {
87 #if !SILVERLIGHT
88                 if (hashCodeDelegate == null) {
89                     hashCodeDelegate = GetHashCodeDelegate();
90                 }
91
92                 hash = hashCodeDelegate(Name, Name.Length, 0);
93 #else
94
95                 hash = Name.GetHashCode() /*+ Namespace.GetHashCode()*/; // for perf reasons we are not taking ns's hashcode.
96 #endif
97             }
98             return hash;
99         }
100
101         /// <include file='doc\XmlQualifiedName.uex' path='docs/doc[@for="XmlQualifiedName.IsEmpty"]/*' />
102         /// <devdoc>
103         ///    <para>[To be supplied.]</para>
104         /// </devdoc>
105         public bool IsEmpty {
106             get { return Name.Length == 0 && Namespace.Length == 0; }
107         }
108
109         /// <include file='doc\XmlQualifiedName.uex' path='docs/doc[@for="XmlQualifiedName.ToString"]/*' />
110         /// <devdoc>
111         ///    <para>[To be supplied.]</para>
112         /// </devdoc>
113         public override string ToString() {
114             return Namespace.Length == 0 ? Name : string.Concat(Namespace, ":" , Name);
115         }
116
117         /// <include file='doc\XmlQualifiedName.uex' path='docs/doc[@for="XmlQualifiedName.Equals"]/*' />
118         /// <devdoc>
119         ///    <para>[To be supplied.]</para>
120         /// </devdoc>
121         public override bool Equals(object other) {
122             XmlQualifiedName qname;
123
124             if ((object) this == other) {
125                 return true;
126             }
127
128             qname = other as XmlQualifiedName;
129             if (qname != null) {
130                 return (Name == qname.Name && Namespace == qname.Namespace);
131             }
132             return false;
133         }
134
135         /// <include file='doc\XmlQualifiedName.uex' path='docs/doc[@for="XmlQualifiedName.operator=="]/*' />
136         /// <devdoc>
137         ///    <para>[To be supplied.]</para>
138         /// </devdoc>
139         public static bool operator ==(XmlQualifiedName a, XmlQualifiedName b) {
140             if ((object) a == (object) b)
141                 return true;
142
143             if ((object) a == null || (object) b == null)
144                 return false;
145
146             return (a.Name == b.Name && a.Namespace == b.Namespace);
147         }
148
149         /// <include file='doc\XmlQualifiedName.uex' path='docs/doc[@for="XmlQualifiedName.operator!="]/*' />
150         /// <devdoc>
151         ///    <para>[To be supplied.]</para>
152         /// </devdoc>
153         public static bool operator !=(XmlQualifiedName a, XmlQualifiedName b) {
154             return !(a == b);
155         }
156
157         /// <include file='doc\XmlQualifiedName.uex' path='docs/doc[@for="XmlQualifiedName.ToString1"]/*' />
158         /// <devdoc>
159         ///    <para>[To be supplied.]</para>
160         /// </devdoc>
161         public static string ToString(string name, string ns) {
162             return ns == null || ns.Length == 0 ? name : ns + ":" + name;
163         }
164
165 #if !SILVERLIGHT // These methods are not used in Silverlight
166         [SecuritySafeCritical]
167 #if !MOBILE
168         [ReflectionPermission(SecurityAction.Assert, Unrestricted = true)]
169 #endif
170         private static HashCodeOfStringDelegate GetHashCodeDelegate() {
171              // If we are using randomized hashing and we find the Marving hash method, we use that
172              // Otherwise, we use the old string hashing function.
173  
174              if (!IsRandomizedHashingDisabled())
175              {
176                 MethodInfo getHashCodeMethodInfo = typeof(String).GetMethod("InternalMarvin32HashString", BindingFlags.NonPublic | BindingFlags.Static);
177                  if (getHashCodeMethodInfo != null)
178                  {
179                     return (HashCodeOfStringDelegate)Delegate.CreateDelegate(typeof(HashCodeOfStringDelegate), getHashCodeMethodInfo);
180                  }
181                 // This will fall through and return a delegate to the old hash function
182                 Debug.Assert(false, "Randomized hashing is not supported.");
183             }
184             return new HashCodeOfStringDelegate(GetHashCodeOfString);
185         }
186
187 #if MONO
188         static bool IsRandomizedHashingDisabled () 
189         {
190             return false;
191         }
192 #else
193         [SecuritySafeCritical]
194         [RegistryPermission(SecurityAction.Assert, Unrestricted = true)]
195         private static bool IsRandomizedHashingDisabled() {
196             const string regValueName = "DisableRandomizedHashingOnXmlQualifiedName";
197             bool disableHashing = false; // default value
198             if (!ReadBoolFromXmlRegistrySettings(Registry.CurrentUser, regValueName, ref disableHashing)) {
199                 ReadBoolFromXmlRegistrySettings(Registry.LocalMachine, regValueName, ref disableHashing);
200             }
201             return disableHashing;
202         }
203
204         [SecurityCritical]
205         private static bool ReadBoolFromXmlRegistrySettings(RegistryKey hive, string regValueName, ref bool value) {
206             const string regValuePath = @"SOFTWARE\Microsoft\.NETFramework\XML";
207             try {
208                 using (RegistryKey xmlRegKey = hive.OpenSubKey(regValuePath, false)) {
209                     if (xmlRegKey != null) {
210                         if (xmlRegKey.GetValueKind(regValueName) == RegistryValueKind.DWord) {
211                             value = ((int)xmlRegKey.GetValue(regValueName)) == 1;
212                             return true;
213                         }
214                     }
215                 }
216             }
217             catch { /* use the default if we couldn't read the key */ }
218             return false;
219         }
220 #endif
221         private static int GetHashCodeOfString(string s, int length, long additionalEntropy)
222         {
223             // This is the fallback method for calling the regular hashcode method
224             return s.GetHashCode();
225         }
226                 
227         // --------- Some useful internal stuff -----------------
228         internal void Init(string name, string ns) {
229             Debug.Assert(name != null && ns != null);
230             this.name = name;
231             this.ns = ns;
232             this.hash = 0;
233         }
234         
235         internal void SetNamespace(string ns) {
236             Debug.Assert(ns != null);
237             this.ns = ns; //Not changing hash since ns is not used to compute hashcode
238         }
239
240         internal void Verify() {
241             XmlConvert.VerifyNCName(name);
242             if (ns.Length != 0) {
243                 XmlConvert.ToUri(ns);
244             }
245         }
246
247         internal void Atomize(XmlNameTable nameTable) {
248             Debug.Assert(name != null);
249             name = nameTable.Add(name);
250             ns = nameTable.Add(ns);
251         }
252
253         internal static XmlQualifiedName Parse(string s, IXmlNamespaceResolver nsmgr, out string prefix) {
254             string localName;
255             ValidateNames.ParseQNameThrow(s, out prefix, out localName);
256
257             string uri = nsmgr.LookupNamespace(prefix);
258             if (uri == null) {
259                 if (prefix.Length != 0) {
260                     throw new XmlException(Res.Xml_UnknownNs, prefix);
261                 }
262                 else { //Re-map namespace of empty prefix to string.Empty when there is no default namespace declared
263                     uri = string.Empty;
264                 }
265             }
266             return new XmlQualifiedName(localName, uri);
267         }
268
269         internal XmlQualifiedName Clone() {
270             return (XmlQualifiedName)MemberwiseClone();
271         }
272
273         internal static int Compare(XmlQualifiedName a, XmlQualifiedName b) {
274             if (null == a) {
275                 return (null == b) ? 0 : -1;
276             }   
277             if (null == b) {
278                 return 1;
279             }
280             int i = String.CompareOrdinal(a.Namespace, b.Namespace);
281             if (i == 0) {
282                 i = String.CompareOrdinal(a.Name, b.Name);
283             }
284             return i;
285         }
286 #endif
287     }
288 }
289