Merge pull request #347 from JamesB7/master
[mono.git] / mcs / class / System.Xml.Linq / System.Xml.Linq / XNodeEqualityComparer.cs
1 //
2 // Authors:
3 //   Atsushi Enomoto
4 //
5 // Copyright 2007 Novell (http://www.novell.com)
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining
8 // a copy of this software and associated documentation files (the
9 // "Software"), to deal in the Software without restriction, including
10 // without limitation the rights to use, copy, modify, merge, publish,
11 // distribute, sublicense, and/or sell copies of the Software, and to
12 // permit persons to whom the Software is furnished to do so, subject to
13 // the following conditions:
14 // 
15 // The above copyright notice and this permission notice shall be
16 // included in all copies or substantial portions of the Software.
17 // 
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 //
26
27 using System;
28 using System.Collections;
29 using System.Collections.Generic;
30
31 using XPI = System.Xml.Linq.XProcessingInstruction;
32
33 namespace System.Xml.Linq
34 {
35         public sealed class XNodeEqualityComparer : IEqualityComparer, IEqualityComparer<XNode>
36         {
37                 public XNodeEqualityComparer ()
38                 {
39                 }
40
41                 public bool Equals (XNode x, XNode y)
42                 {
43                         if (x == null)
44                                 return y == null;
45                         else if (y == null)
46                                 return false;
47                         //throw new NotImplementedException ();
48                         if (x.NodeType != y.NodeType)
49                                 return false;
50                         switch (x.NodeType) {
51                         case XmlNodeType.Document:
52                                 XDocument doc1 = (XDocument) x;
53                                 XDocument doc2 = (XDocument) y;
54                                 if (!Equals (doc1.Declaration, doc2.Declaration))
55                                         return false;
56                                 IEnumerator<XNode> id2 = doc2.Nodes ().GetEnumerator ();
57                                 foreach (XNode n in doc1.Nodes ()) {
58                                         if (!id2.MoveNext ())
59                                                 return false;
60                                         if (!Equals (n, id2.Current))
61                                                 return false;
62                                 }
63                                 return !id2.MoveNext ();
64                         case XmlNodeType.Element:
65                                 XElement e1 = (XElement) x;
66                                 XElement e2 = (XElement) y;
67                                 if (e1.Name != e2.Name)
68                                         return false;
69                                 IEnumerator<XAttribute> ia2 = e2.Attributes ().GetEnumerator ();
70                                 foreach (XAttribute n in e1.Attributes ()) {
71                                         if (!ia2.MoveNext ())
72                                                 return false;
73                                         if (!Equals (n, ia2.Current))
74                                                 return false;
75                                 }
76                                 if (ia2.MoveNext ())
77                                         return false;
78                                 IEnumerator<XNode> ie2 = e2.Nodes ().GetEnumerator ();
79                                 foreach (XNode n in e1.Nodes ()) {
80                                         if (!ie2.MoveNext ())
81                                                 return false;
82                                         if (!Equals (n, ie2.Current))
83                                                 return false;
84                                 }
85                                 return !ie2.MoveNext ();
86                         case XmlNodeType.Comment:
87                                 XComment c1 = (XComment) x;
88                                 XComment c2 = (XComment) y;
89                                 return c1.Value == c2.Value;
90                         case XmlNodeType.ProcessingInstruction:
91                                 XPI p1 = (XPI) x;
92                                 XPI p2 = (XPI) y;
93                                 return p1.Target == p2.Target && p1.Data == p2.Data;
94                         case XmlNodeType.DocumentType:
95                                 XDocumentType d1 = (XDocumentType) x;
96                                 XDocumentType d2 = (XDocumentType) y;
97                                 return d1.Name == d2.Name &&
98                                        d1.PublicId == d2.PublicId &&
99                                        d1.SystemId == d2.SystemId &&
100                                        d1.InternalSubset == d2.InternalSubset;
101                         case XmlNodeType.Text:
102                                 return ((XText) x).Value == ((XText) y).Value;
103                         }
104                         throw new Exception ("INTERNAL ERROR: should not happen");
105                 }
106
107                 bool Equals (XAttribute a1, XAttribute a2)
108                 {
109                         if (a1 == null)
110                                 return a2 == null;
111                         else if (a2 == null)
112                                 return false;
113                         return a1.Name == a2.Name && a1.Value == a2.Value;
114                 }
115
116                 bool Equals (XDeclaration d1, XDeclaration d2)
117                 {
118                         if (d1 == null)
119                                 return d2 == null;
120                         else if (d2 == null)
121                                 return false;
122                         return d1.Version == d2.Version &&
123                                d1.Encoding == d2.Encoding &&
124                                d1.Standalone == d2.Standalone;
125                 }
126
127                 bool IEqualityComparer.Equals (object n1, object n2)
128                 {
129                         return Equals ((XNode) n1, (XNode) n2);
130                 }
131
132                 int GetHashCode (XDeclaration d)
133                 {
134                         if (d == null)
135                                 return 0;
136                         return (d.Version.GetHashCode () << 7) ^
137                                (d.Encoding.GetHashCode () << 6) ^
138                                d.Standalone.GetHashCode ();
139                 }
140
141                 public int GetHashCode (XNode obj)
142                 {
143                         if (obj == null)
144                                 return 0;
145                         int h = ((int) obj.NodeType << 6);
146                         switch (obj.NodeType) {
147                         case XmlNodeType.Document:
148                                 XDocument doc = (XDocument) obj;
149                                 h = h ^ GetHashCode (doc.Declaration);
150                                 foreach (XNode n in doc.Nodes ())
151                                         h = h ^ (n.GetHashCode () << 5);
152                                 break;
153                         case XmlNodeType.Element:
154                                 XElement el = (XElement) obj;
155                                 h = h ^ (el.Name.GetHashCode () << 3);
156                                 foreach (XAttribute a in el.Attributes ())
157                                         h = h ^ (a.GetHashCode () << 7);
158                                 foreach (XNode n in el.Nodes ())
159                                         h = h ^ (n.GetHashCode () << 6);
160                                 break;
161                         case XmlNodeType.Comment:
162                                 h = h ^ ((XComment) obj).Value.GetHashCode ();
163                                 break;
164                         case XmlNodeType.ProcessingInstruction:
165                                 XPI pi = (XPI) obj;
166                                 h = h ^ ((pi.Target.GetHashCode () << 6) + pi.Data.GetHashCode ());
167                                 break;
168                         case XmlNodeType.DocumentType:
169                                 XDocumentType dtd = (XDocumentType) obj;
170                                 h = h ^ (dtd.Name.GetHashCode () << 7) ^
171                                     (dtd.PublicId.GetHashCode () << 6) ^
172                                     (dtd.SystemId.GetHashCode () << 5) ^
173                                     (dtd.InternalSubset.GetHashCode () << 4);
174                                 break;
175                         case XmlNodeType.Text:
176                                 h = h ^ (((XText) obj).GetHashCode ());
177                                 break;
178                         }
179                         return h;
180                 }
181
182                 int IEqualityComparer.GetHashCode (object obj)
183                 {
184                         return GetHashCode ((XNode) obj);
185                 }
186         }
187 }