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