1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4 
5 namespace System.ServiceModel.Security
6 {
7     using System.IO;
8     using System.ServiceModel.Channels;
9     using System.Text;
10     using System.Xml;
11 
12     static class XmlHelper
13     {
AddNamespaceDeclaration(XmlDictionaryWriter writer, string prefix, XmlDictionaryString ns)14         internal static void AddNamespaceDeclaration(XmlDictionaryWriter writer, string prefix, XmlDictionaryString ns)
15         {
16             string p = writer.LookupPrefix(ns.Value);
17             if (p == null || p != prefix)
18             {
19                 writer.WriteXmlnsAttribute(prefix, ns);
20             }
21         }
22 
EnsureNamespaceDefined(XmlDictionaryWriter writer, XmlDictionaryString ns, string defaultPrefix)23         internal static string EnsureNamespaceDefined(XmlDictionaryWriter writer, XmlDictionaryString ns, string defaultPrefix)
24         {
25             string p = writer.LookupPrefix(ns.Value);
26             if (p == null)
27             {
28                 writer.WriteXmlnsAttribute(defaultPrefix, ns);
29                 p = defaultPrefix;
30             }
31 
32             return p;
33         }
34 
GetAttributeValueAsQName(XmlReader reader, string attributeName)35         internal static XmlQualifiedName GetAttributeValueAsQName(XmlReader reader, string attributeName)
36         {
37             string qname = reader.GetAttribute(attributeName);
38             if (qname == null)
39             {
40                 return null;
41             }
42             return GetValueAsQName(reader, qname);
43         }
44 
45         /// <summary>
46         /// Enforces that parent has exactly 1 child of type XML element and nothing else (barring comments and whitespaces)
47         /// and returns the child
48         /// </summary>
GetChildElement(XmlElement parent)49         internal static XmlElement GetChildElement(XmlElement parent)
50         {
51             if (parent == null)
52             {
53                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("parent");
54             }
55 
56             XmlElement result = null;
57             for (int i = 0; i < parent.ChildNodes.Count; ++i)
58             {
59                 XmlNode child = parent.ChildNodes[i];
60                 if (child.NodeType == XmlNodeType.Whitespace || child.NodeType == XmlNodeType.Comment)
61                 {
62                     continue;
63                 }
64                 else if (child.NodeType == XmlNodeType.Element && result == null)
65                 {
66                     result = ((XmlElement) child);
67                 }
68                 else
69                 {
70                     OnUnexpectedChildNodeError(parent, child);
71                 }
72             }
73 
74             if (result == null)
75             {
76                 OnChildNodeTypeMissing(parent, XmlNodeType.Element);
77             }
78 
79             return result;
80         }
81 
GetChildElement(XmlElement parent, string childLocalName, string childNamespace)82         internal static XmlElement GetChildElement(XmlElement parent, string childLocalName, string childNamespace)
83         {
84             if (parent == null)
85             {
86                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("parent");
87             }
88 
89             for (int i = 0; i < parent.ChildNodes.Count; ++i)
90             {
91                 XmlNode child = parent.ChildNodes[i];
92 
93                 if (child.NodeType == XmlNodeType.Whitespace || child.NodeType == XmlNodeType.Comment)
94                 {
95                     continue;
96                 }
97                 else if (child.NodeType == XmlNodeType.Element)
98                 {
99                     if (child.LocalName == childLocalName && child.NamespaceURI == childNamespace)
100                     {
101                         return ((XmlElement) child);
102                     }
103                 }
104                 else
105                 {
106                     OnUnexpectedChildNodeError(parent, child);
107                 }
108             }
109 
110             return null;
111         }
112 
GetValueAsQName(XmlReader reader, string value)113         internal static XmlQualifiedName GetValueAsQName(XmlReader reader, string value)
114         {
115             string prefix;
116             string name;
117             SplitIntoPrefixAndName(value, out prefix, out name);
118             string ns = reader.LookupNamespace(prefix);
119             if (ns == null && prefix.Length > 0)
120             {
121                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.CouldNotFindNamespaceForPrefix, prefix)));
122             }
123             return new XmlQualifiedName(name, ns);
124         }
125 
GetWhiteSpace(XmlReader reader)126         internal static string GetWhiteSpace(XmlReader reader)
127         {
128             string s = null;
129             StringBuilder sb = null;
130             while (reader.NodeType == XmlNodeType.Whitespace || reader.NodeType == XmlNodeType.SignificantWhitespace)
131             {
132                 if (sb != null)
133                 {
134                     sb.Append(reader.Value);
135                 }
136                 else if (s != null)
137                 {
138                     sb = new StringBuilder(s);
139                     sb.Append(reader.Value);
140                     s = null;
141                 }
142                 else
143                 {
144                     s = reader.Value;
145                 }
146                 if (!reader.Read())
147                 {
148                     break;
149                 }
150             }
151             return sb != null ? sb.ToString() : s;
152         }
153 
IsWhitespaceOrComment(XmlReader reader)154         internal static bool IsWhitespaceOrComment(XmlReader reader)
155         {
156             if (reader.NodeType == XmlNodeType.Comment)
157             {
158                 return true;
159             }
160             else if (reader.NodeType == XmlNodeType.Whitespace)
161             {
162                 return true;
163             }
164             else
165             {
166                 return false;
167             }
168         }
169 
OnChildNodeTypeMissing(string parentName, XmlNodeType expectedNodeType)170         internal static void OnChildNodeTypeMissing(string parentName, XmlNodeType expectedNodeType)
171         {
172             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.ChildNodeTypeMissing, parentName, expectedNodeType)));
173         }
174 
OnChildNodeTypeMissing(XmlElement parent, XmlNodeType expectedNodeType)175         internal static void OnChildNodeTypeMissing(XmlElement parent, XmlNodeType expectedNodeType)
176         {
177             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.ChildNodeTypeMissing, parent.Name, expectedNodeType)));
178         }
179 
OnEmptyElementError(XmlReader r)180         internal static void OnEmptyElementError(XmlReader r)
181         {
182             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.EmptyXmlElementError, r.Name)));
183         }
184 
OnEmptyElementError(XmlElement e)185         internal static void OnEmptyElementError(XmlElement e)
186         {
187             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.EmptyXmlElementError, e.Name)));
188         }
189 
OnEOF()190         internal static void OnEOF()
191         {
192             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.UnexpectedEndOfFile)));
193         }
194 
OnNamespaceMissing(string prefix)195         internal static void OnNamespaceMissing(string prefix)
196         {
197             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.CouldNotFindNamespaceForPrefix, prefix)));
198         }
199 
OnRequiredAttributeMissing(string attrName, string elementName)200         internal static void OnRequiredAttributeMissing(string attrName, string elementName)
201         {
202             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.RequiredAttributeMissing, attrName, elementName)));
203         }
204 
OnRequiredElementMissing(string elementName, string elementNamespace)205         internal static void OnRequiredElementMissing(string elementName, string elementNamespace)
206         {
207             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.ExpectedElementMissing, elementName, elementNamespace)));
208         }
209 
OnUnexpectedChildNodeError(string parentName, XmlReader r)210         internal static void OnUnexpectedChildNodeError(string parentName, XmlReader r)
211         {
212             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.UnexpectedXmlChildNode, r.Name, r.NodeType, parentName)));
213         }
214 
OnUnexpectedChildNodeError(XmlElement parent, XmlNode n)215         internal static void OnUnexpectedChildNodeError(XmlElement parent, XmlNode n)
216         {
217             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new XmlException(SR.GetString(SR.UnexpectedXmlChildNode, n.Name, n.NodeType, parent.Name)));
218         }
219 
ReadEmptyElementAndRequiredAttribute(XmlDictionaryReader reader, XmlDictionaryString name, XmlDictionaryString namespaceUri, XmlDictionaryString attributeName, out string prefix)220         internal static string ReadEmptyElementAndRequiredAttribute(XmlDictionaryReader reader,
221             XmlDictionaryString name, XmlDictionaryString namespaceUri, XmlDictionaryString attributeName,
222             out string prefix)
223         {
224             reader.MoveToStartElement(name, namespaceUri);
225             prefix = reader.Prefix;
226             bool isEmptyElement = reader.IsEmptyElement;
227             string value = reader.GetAttribute(attributeName, null);
228             if (value == null)
229             {
230                 OnRequiredAttributeMissing(attributeName.Value, null);
231             }
232             reader.Read();
233 
234             if (!isEmptyElement)
235             {
236                 reader.ReadEndElement();
237             }
238             return value;
239         }
240 
GetRequiredNonEmptyAttribute(XmlDictionaryReader reader, XmlDictionaryString name, XmlDictionaryString ns)241         internal static string GetRequiredNonEmptyAttribute(XmlDictionaryReader reader, XmlDictionaryString name, XmlDictionaryString ns)
242         {
243             string value = reader.GetAttribute(name, ns);
244             if (value == null || value.Length == 0)
245             {
246                 OnRequiredAttributeMissing(name.Value, reader == null ? null : reader.Name);
247             }
248             return value;
249         }
250 
GetRequiredBase64Attribute(XmlDictionaryReader reader, XmlDictionaryString name, XmlDictionaryString ns)251         internal static byte[] GetRequiredBase64Attribute(XmlDictionaryReader reader, XmlDictionaryString name, XmlDictionaryString ns)
252         {
253             if (!reader.MoveToAttribute(name.Value,  ns == null ? null : ns.Value))
254             {
255                 OnRequiredAttributeMissing(name.Value, ns == null ? null : ns.Value);
256             }
257             byte[] value = reader.ReadContentAsBase64();
258             if (value == null || value.Length == 0)
259             {
260                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
261                     new XmlException(SR.GetString(SR.EmptyBase64Attribute, name, ns)));
262             }
263 
264             return value;
265         }
266 
ReadTextElementAsTrimmedString(XmlElement element)267         internal static string ReadTextElementAsTrimmedString(XmlElement element)
268         {
269             if (element == null)
270             {
271                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("element");
272             }
273 
274             using (XmlReader reader = new XmlNodeReader(element))
275             {
276                 reader.MoveToContent();
277                 return XmlUtil.Trim(reader.ReadElementContentAsString());
278             }
279         }
280 
SplitIntoPrefixAndName(string qName, out string prefix, out string name)281         internal static void SplitIntoPrefixAndName(string qName, out string prefix, out string name)
282         {
283             string[] parts = qName.Split(':');
284             if (parts.Length > 2)
285             {
286                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.InvalidQName));
287             }
288 
289             if (parts.Length == 2)
290             {
291                 prefix = parts[0].Trim();
292                 name = parts[1].Trim();
293             }
294             else
295             {
296                 prefix = string.Empty;
297                 name = qName.Trim();
298             }
299         }
300 
ValidateIdPrefix(string idPrefix)301         internal static void ValidateIdPrefix(string idPrefix)
302         {
303             if (idPrefix == null)
304             {
305                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("idPrefix"));
306             }
307 
308             if (idPrefix.Length == 0)
309             {
310                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("idPrefix", SR.GetString(SR.ValueMustBeGreaterThanZero)));
311             }
312 
313             if ((!Char.IsLetter(idPrefix[0]) && idPrefix[0] != '_'))
314             {
315                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("idPrefix", SR.GetString(SR.InValidateIdPrefix, idPrefix[0])));
316             }
317 
318             for (int i = 1; i < idPrefix.Length; i++)
319             {
320                 char c = idPrefix[i];
321                 if (!Char.IsLetter(c) && !Char.IsNumber(c) && c != '.' && c != '_' && c != '-')
322                 {
323                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("idPrefix", SR.GetString(SR.InValidateId, idPrefix[i])));
324                 }
325             }
326         }
327 
GetAttributeAsUniqueId(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString ns)328         internal static UniqueId GetAttributeAsUniqueId(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString ns)
329         {
330             return GetAttributeAsUniqueId(reader, localName.Value, (ns != null ? ns.Value : null));
331         }
332 
GetAttributeAsUniqueId(XmlDictionaryReader reader, string name, string ns)333         static UniqueId GetAttributeAsUniqueId(XmlDictionaryReader reader, string name, string ns)
334         {
335             if (!reader.MoveToAttribute(name, ns))
336             {
337                 return null;
338             }
339 
340             UniqueId id = reader.ReadContentAsUniqueId();
341             reader.MoveToElement();
342 
343             return id;
344         }
345 #if NO
WriteAttributeStringAsUniqueId(XmlWriter writer, string localName, string ns, UniqueId id)346         static public void WriteAttributeStringAsUniqueId(XmlWriter writer, string localName, string ns, UniqueId id)
347         {
348             WriteAttributeStringAsUniqueId(XmlDictionaryWriter.CreateDictionaryWriter(writer), localName, ns, id);
349         }
350 
WriteAttributeStringAsUniqueId(XmlWriter writer, string prefix, string localName, string ns, UniqueId id)351         static public void WriteAttributeStringAsUniqueId(XmlWriter writer, string prefix, string localName, string ns, UniqueId id)
352         {
353             WriteAttributeStringAsUniqueId(XmlDictionaryWriter.CreateDictionaryWriter(writer), prefix, localName, ns, id);
354         }
355 
WriteAttributeStringAsUniqueId(XmlDictionaryWriter writer, string localName, string ns, UniqueId id)356         static public void WriteAttributeStringAsUniqueId(XmlDictionaryWriter writer, string localName, string ns, UniqueId id)
357         {
358             WriteAttributeStringAsUniqueId(writer, null, localName, ns, id);
359         }
360 
WriteAttributeStringAsUniqueId(XmlDictionaryWriter writer, string prefix, string localName, string ns, UniqueId id)361         static public void WriteAttributeStringAsUniqueId(XmlDictionaryWriter writer, string prefix, string localName, string ns, UniqueId id)
362         {
363             writer.WriteStartAttribute(prefix, localName, ns);
364             writer.WriteValue(id);
365             writer.WriteEndAttribute();
366         }
367 
WriteAttributeStringAsUniqueId(XmlDictionaryWriter writer, XmlDictionaryString localName, XmlDictionaryString ns, UniqueId id)368         static public void WriteAttributeStringAsUniqueId(XmlDictionaryWriter writer, XmlDictionaryString localName, XmlDictionaryString ns, UniqueId id)
369         {
370             WriteAttributeStringAsUniqueId(writer, null, localName, ns, id);
371         }
372 #endif
WriteAttributeStringAsUniqueId(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString ns, UniqueId id)373         static public void WriteAttributeStringAsUniqueId(XmlDictionaryWriter writer, string prefix, XmlDictionaryString localName, XmlDictionaryString ns, UniqueId id)
374         {
375             writer.WriteStartAttribute(prefix, localName, ns);
376             writer.WriteValue(id);
377             writer.WriteEndAttribute();
378         }
379 
WriteElementStringAsUniqueId(XmlWriter writer, string localName, UniqueId id)380         static public void WriteElementStringAsUniqueId(XmlWriter writer, string localName, UniqueId id)
381         {
382             writer.WriteStartElement(localName);
383             writer.WriteValue(id);
384             writer.WriteEndElement();
385         }
386 #if NO
WriteElementStringAsUniqueId(XmlDictionaryWriter writer, string localName, UniqueId id)387         static public void WriteElementStringAsUniqueId(XmlDictionaryWriter writer, string localName, UniqueId id)
388         {
389             WriteElementStringAsUniqueId(writer, localName, null, id);
390         }
391 
WriteElementStringAsUniqueId(XmlDictionaryWriter writer, string localName, string ns, UniqueId id)392         static public void WriteElementStringAsUniqueId(XmlDictionaryWriter writer, string localName, string ns, UniqueId id)
393         {
394             writer.WriteStartElement(localName, ns);
395             writer.WriteValue(id);
396             writer.WriteEndElement();
397         }
398 #endif
WriteElementStringAsUniqueId(XmlDictionaryWriter writer, XmlDictionaryString localName, XmlDictionaryString ns, UniqueId id)399         static public void WriteElementStringAsUniqueId(XmlDictionaryWriter writer, XmlDictionaryString localName, XmlDictionaryString ns, UniqueId id)
400         {
401             writer.WriteStartElement(localName, ns);
402             writer.WriteValue(id);
403             writer.WriteEndElement();
404         }
405 
WriteElementContentAsInt64(XmlDictionaryWriter writer, XmlDictionaryString localName, XmlDictionaryString ns, Int64 value)406         static public void WriteElementContentAsInt64(XmlDictionaryWriter writer, XmlDictionaryString localName, XmlDictionaryString ns, Int64 value)
407         {
408             writer.WriteStartElement(localName, ns);
409             writer.WriteValue(value);
410             writer.WriteEndElement();
411         }
412 
ReadElementContentAsInt64(XmlDictionaryReader reader)413         static public Int64 ReadElementContentAsInt64(XmlDictionaryReader reader)
414         {
415             reader.ReadFullStartElement();
416             Int64 i = reader.ReadContentAsLong();
417             reader.ReadEndElement();
418             return i;
419         }
420 
WriteStringAsUniqueId(XmlDictionaryWriter writer, UniqueId id)421         static public void WriteStringAsUniqueId(XmlDictionaryWriter writer, UniqueId id)
422         {
423             writer.WriteValue(id);
424         }
425 
ReadElementStringAsUniqueId(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString ns)426         static public UniqueId ReadElementStringAsUniqueId(XmlDictionaryReader reader, XmlDictionaryString localName, XmlDictionaryString ns)
427         {
428             if (reader.IsStartElement(localName, ns) && reader.IsEmptyElement)
429             {
430                 reader.Read();
431                 return new UniqueId(string.Empty);
432             }
433 
434             reader.ReadStartElement(localName, ns);
435             UniqueId id = reader.ReadContentAsUniqueId();
436             reader.ReadEndElement();
437             return id;
438         }
439 
ReadElementStringAsUniqueId(XmlDictionaryReader reader)440         static public UniqueId ReadElementStringAsUniqueId(XmlDictionaryReader reader)
441         {
442             if (reader.IsStartElement() && reader.IsEmptyElement)
443             {
444                 reader.Read();
445                 return new UniqueId(string.Empty);
446             }
447 
448             reader.ReadStartElement();
449             UniqueId id = reader.ReadContentAsUniqueId();
450             reader.ReadEndElement();
451             return id;
452         }
453 #if NO
ReadEmptyElementAndRequiredAttributeAsUniqueId(XmlDictionaryReader reader, XmlDictionaryString name, XmlDictionaryString namespaceUri, XmlDictionaryString attributeName, out string prefix)454         internal static UniqueId ReadEmptyElementAndRequiredAttributeAsUniqueId(XmlDictionaryReader reader, XmlDictionaryString name, XmlDictionaryString namespaceUri, XmlDictionaryString attributeName, out string prefix)
455         {
456             string s = ReadEmptyElementAndRequiredAttribute(reader, name, namespaceUri, attributeName, out prefix);
457 
458             if (s == null)
459                 return null;
460 
461             return new UniqueId(s);
462         }
463 
ReadTextElementAsUniqueId(XmlDictionaryReader reader)464         static public UniqueId ReadTextElementAsUniqueId(XmlDictionaryReader reader)
465         {
466             return new UniqueId(ReadTextElement(reader));
467         }
468 #endif
ReadTextElementAsUniqueId(XmlElement element)469         static public UniqueId ReadTextElementAsUniqueId(XmlElement element)
470         {
471             return new UniqueId(ReadTextElementAsTrimmedString(element));
472         }
473 #if NO
GetAttributeAsUniqueId(XmlElement element, string localName, string ns)474         static public UniqueId GetAttributeAsUniqueId(XmlElement element, string localName, string ns)
475         {
476             XmlAttribute attr = element.Attributes[localName, ns];
477 
478             if (attr == null)
479                 return null;
480 
481             return new UniqueId(attr.Value);
482         }
483 #endif
484     }
485 }
486