//---------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------- namespace System.ServiceModel.Discovery { using System; using System.Collections.ObjectModel; using System.Globalization; using System.Runtime; using System.Text; using System.Xml; using SR2 = System.ServiceModel.Discovery.SR; static class SerializationUtility { static char[] whiteSpaceChars = new char[] { ' ', '\t', '\n', '\r' }; public static XmlQualifiedName ParseQName(string prefixedQName, XmlReader reader) { Fx.Assert(prefixedQName != null, "The prefixedQName must be non null."); Fx.Assert(reader != null, "The reader must be non null."); int index = prefixedQName.IndexOf(':'); string ns; string localname; if (index != -1) { string prefix = prefixedQName.Substring(0, index); ns = reader.LookupNamespace(prefix); if (ns == null) { throw FxTrace.Exception.AsError(new XmlException(SR2.DiscoveryXmlQNamePrefixNotDefined(prefix, prefixedQName))); } localname = prefixedQName.Substring(index + 1); if (localname == string.Empty) { throw FxTrace.Exception.AsError(new XmlException(SR2.DiscoveryXmlQNameLocalnameNotDefined(prefixedQName))); } } else { ns = string.Empty; localname = prefixedQName; } localname = XmlConvert.DecodeName(localname); return new XmlQualifiedName(localname, ns); } public static void ParseQNameList(string listOfQNamesAsString, Collection qNameCollection, XmlReader reader) { Fx.Assert(listOfQNamesAsString != null, "The listOfQNamesAsString must be non null."); Fx.Assert(qNameCollection != null, "The qNameCollection must be non null."); Fx.Assert(reader != null, "The reader must be non null."); string[] prefixedQNames = listOfQNamesAsString.Split(whiteSpaceChars, StringSplitOptions.RemoveEmptyEntries); if (prefixedQNames.Length > 0) { for (int i = 0; i < prefixedQNames.Length; i++) { qNameCollection.Add(ParseQName(prefixedQNames[i], reader)); } } } public static void ParseUriList(string listOfUrisAsString, Collection uriCollection, UriKind uriKind) { Fx.Assert(listOfUrisAsString != null, "The listOfUrisAsString must be non null."); Fx.Assert(uriCollection != null, "The uriCollection must be non null."); string[] uriStrings = listOfUrisAsString.Split(whiteSpaceChars, StringSplitOptions.RemoveEmptyEntries); if (uriStrings.Length > 0) { for (int i = 0; i < uriStrings.Length; i++) { try { uriCollection.Add(new Uri(uriStrings[i], uriKind)); } catch (FormatException fe) { if (uriKind == UriKind.Absolute) { throw FxTrace.Exception.AsError(new XmlException(SR2.DiscoveryXmlAbsoluteUriFormatError(uriStrings[i]), fe)); } else { throw FxTrace.Exception.AsError(new XmlException(SR2.DiscoveryXmlUriFormatError(uriStrings[i]), fe)); } } } } } public static long ReadUInt(string uintString, string notFoundExceptionString, string exceptionString) { long result; if (uintString == null) { throw FxTrace.Exception.AsError(new XmlException(notFoundExceptionString)); } try { result = XmlConvert.ToUInt32(uintString); } catch (FormatException fe) { throw FxTrace.Exception.AsError(new XmlException(exceptionString, fe)); } catch (OverflowException oe) { throw FxTrace.Exception.AsError(new XmlException(exceptionString, oe)); } return result; } static void PrepareQNameString(StringBuilder listOfQNamesString, ref bool emptyNsDeclared, ref int prefixCount, XmlWriter writer, XmlQualifiedName qname) { string prefix; string encodedLocalName = XmlConvert.EncodeLocalName(qname.Name.Trim()); if (qname.Namespace.Length == 0) { if (!emptyNsDeclared) { writer.WriteAttributeString("xmlns", string.Empty, null, string.Empty); emptyNsDeclared = true; } prefix = null; } else { prefix = writer.LookupPrefix(qname.Namespace); if (prefix == null) { prefix = "dp" + prefixCount++; writer.WriteAttributeString("xmlns", prefix, null, qname.Namespace); } } if (!string.IsNullOrEmpty(prefix)) { listOfQNamesString.AppendFormat(CultureInfo.InvariantCulture, "{0}:{1}", prefix, encodedLocalName); } else { listOfQNamesString.AppendFormat(CultureInfo.InvariantCulture, "{0}", encodedLocalName); } } public static void WriteQName(XmlWriter writer, XmlQualifiedName qname) { Fx.Assert(writer != null, "The writer must be non null."); Fx.Assert(qname != null, "The qnames must be non null."); StringBuilder qNameString = new StringBuilder(); int prefixCount = 0; bool emptyNsDeclared = false; PrepareQNameString(qNameString, ref emptyNsDeclared, ref prefixCount, writer, qname); writer.WriteString(qNameString.ToString()); } public static void WriteListOfQNames(XmlWriter writer, Collection qnames) { Fx.Assert(writer != null, "The writer must be non null."); Fx.Assert(qnames != null, "The qnames must be non null."); int prefixCount = 0; bool emptyNsDeclared = false; StringBuilder listOfQNamesString = new StringBuilder(); foreach (XmlQualifiedName qname in qnames) { if (listOfQNamesString.Length != 0) { listOfQNamesString.Append(' '); } PrepareQNameString(listOfQNamesString, ref emptyNsDeclared, ref prefixCount, writer, qname); } writer.WriteString(listOfQNamesString.ToString()); } public static void WriteListOfUris(XmlWriter writer, Collection uris) { Fx.Assert(writer != null, "The writer must be non null."); Fx.Assert(uris != null, "The uris must be non null."); if (uris.Count > 0) { for (int i = 0; i < uris.Count - 1; i++) { writer.WriteString(uris[i].GetComponents(UriComponents.SerializationInfoString, UriFormat.UriEscaped)); writer.WriteWhitespace(" "); } writer.WriteString(uris[uris.Count - 1].GetComponents(UriComponents.SerializationInfoString, UriFormat.UriEscaped)); } } public static int ReadMaxResults(XmlReader reader) { int maxResults = int.MaxValue; if (reader.IsEmptyElement) { reader.Read(); } else { reader.ReadStartElement(); maxResults = reader.ReadContentAsInt(); if (maxResults <= 0) { throw FxTrace.Exception.AsError(new XmlException(SR2.DiscoveryXmlMaxResultsLessThanZero(maxResults))); } reader.ReadEndElement(); } return maxResults; } public static TimeSpan ReadDuration(XmlReader reader) { TimeSpan timeout = TimeSpan.MaxValue; if (reader.IsEmptyElement) { reader.Read(); } else { reader.ReadStartElement(); string timeoutString = reader.ReadString(); timeout = SerializationUtility.ReadTimespan(timeoutString, SR2.DiscoveryXmlDurationDeserializationError(timeoutString)); if (timeout <= TimeSpan.Zero) { throw FxTrace.Exception.AsError(new XmlException(SR2.DiscoveryXmlDurationLessThanZero(timeout)));; } reader.ReadEndElement(); } return timeout; } public static TimeSpan ReadTimespan(string timespanString, string exceptionString) { TimeSpan result; try { result = XmlConvert.ToTimeSpan(timespanString); } catch (FormatException fe) { throw FxTrace.Exception.AsError(new XmlException(exceptionString, fe)); } catch (OverflowException oe) { throw FxTrace.Exception.AsError(new XmlException(exceptionString, oe)); } return result; } public static EndpointAddress ReadEndpointAddress(DiscoveryVersion discoveryVersion, XmlReader reader) { Fx.Assert(discoveryVersion != null, "The discoveryVersion must be non null"); Fx.Assert(reader != null, "The reader must be non null"); if (discoveryVersion == DiscoveryVersion.WSDiscoveryApril2005 || discoveryVersion == DiscoveryVersion.WSDiscoveryCD1) { EndpointAddressAugust2004 endpoint = discoveryVersion.Implementation.EprSerializer.ReadObject(reader) as EndpointAddressAugust2004; if (endpoint == null) { throw FxTrace.Exception.AsError(new XmlException(SR2.DiscoveryXmlEndpointNull)); } return endpoint.ToEndpointAddress(); } else if (discoveryVersion == DiscoveryVersion.WSDiscovery11) { EndpointAddress10 endpoint = discoveryVersion.Implementation.EprSerializer.ReadObject(reader) as EndpointAddress10; if (endpoint == null) { throw FxTrace.Exception.AsError(new XmlException(SR2.DiscoveryXmlEndpointNull)); } return endpoint.ToEndpointAddress(); } else { Fx.Assert("The discoveryVersion parameter cannot be null."); return null; } } public static void ReadContractTypeNames(Collection contractTypeNames, XmlReader reader) { if (reader.IsEmptyElement) { reader.Read(); } else { reader.ReadStartElement(); string listOfQNamesAsStr = reader.ReadString(); if (!string.IsNullOrEmpty(listOfQNamesAsStr)) { SerializationUtility.ParseQNameList(listOfQNamesAsStr, contractTypeNames, reader); } reader.ReadEndElement(); } } public static Uri ReadScopes(Collection scopes, XmlReader reader) { Uri scopeMatchBy = null; if (reader.HasAttributes) { while (reader.MoveToNextAttribute()) { if ((reader.NamespaceURI.Length == 0) && (reader.Name.Equals(ProtocolStrings.SchemaNames.MatchByAttribute))) { string scopeMatchByStr = reader.Value; try { scopeMatchBy = new Uri(scopeMatchByStr, UriKind.RelativeOrAbsolute); } catch (FormatException fe) { throw FxTrace.Exception.AsError(new XmlException(SR2.DiscoveryXmlUriFormatError(scopeMatchByStr), fe)); } break; } } reader.MoveToElement(); } if (reader.IsEmptyElement) { reader.Read(); } else { reader.ReadStartElement(); string listOfUrisAsString = reader.ReadString(); if (!string.IsNullOrEmpty(listOfUrisAsString)) { SerializationUtility.ParseUriList(listOfUrisAsString, scopes, UriKind.Absolute); } reader.ReadEndElement(); } return scopeMatchBy; } public static void ReadListenUris(Collection listenUris, XmlReader reader) { if (reader.IsEmptyElement) { reader.Read(); } else { reader.ReadStartElement(); string listOfUrisAsString = reader.ReadString(); if (!string.IsNullOrEmpty(listOfUrisAsString)) { SerializationUtility.ParseUriList(listOfUrisAsString, listenUris, UriKind.RelativeOrAbsolute); } reader.ReadEndElement(); } } public static int ReadMetadataVersion(XmlReader reader) { reader.ReadStartElement(); int metadataVersion = reader.ReadContentAsInt(); if (metadataVersion < 0) { throw FxTrace.Exception.AsError(new XmlException(SR2.DiscoveryXmlMetadataVersionLessThanZero(metadataVersion))); } reader.ReadEndElement(); return metadataVersion; } public static void WriteEndPointAddress(DiscoveryVersion discoveryVersion, EndpointAddress endpointAddress, XmlWriter writer) { Fx.Assert(discoveryVersion != null, "The discoveryVersion must be non null"); Fx.Assert(writer != null, "The writer must be non null"); if (discoveryVersion == DiscoveryVersion.WSDiscoveryApril2005 || discoveryVersion == DiscoveryVersion.WSDiscoveryCD1) { EndpointAddressAugust2004 endpoint = EndpointAddressAugust2004.FromEndpointAddress(endpointAddress); discoveryVersion.Implementation.EprSerializer.WriteObject(writer, endpoint); } else if (discoveryVersion == DiscoveryVersion.WSDiscovery11) { EndpointAddress10 endpoint = EndpointAddress10.FromEndpointAddress(endpointAddress); discoveryVersion.Implementation.EprSerializer.WriteObject(writer, endpoint); } else { Fx.Assert("The discoveryVersion parameter cannot be null."); } } public static void WriteContractTypeNames(DiscoveryVersion discoveryVersion, Collection contractTypeNames, XmlWriter writer) { if ((contractTypeNames != null) && (contractTypeNames.Count > 0)) { // using the prefix here allows us to redefine the empty namespace // for serializing the QNames is required. writer.WriteStartElement( ProtocolStrings.SchemaNames.DefaultPrefix, ProtocolStrings.SchemaNames.TypesElement, discoveryVersion.Namespace); SerializationUtility.WriteListOfQNames(writer, contractTypeNames); writer.WriteEndElement(); } } public static void WriteScopes(DiscoveryVersion discoveryVersion, Collection scopes, Uri scopeMatchBy, XmlWriter writer) { bool writeScopes = true; if (scopes == null || scopes.Count == 0) { // If there are no scopes defined, we write the Scopes section only if matchBy contract is None. writeScopes = (scopeMatchBy == FindCriteria.ScopeMatchByNone); } if (writeScopes) { writer.WriteStartElement(ProtocolStrings.SchemaNames.ScopesElement, discoveryVersion.Namespace); if (scopeMatchBy != null) { Uri versionDependentScopeMatchBy = discoveryVersion.Implementation.ToVersionDependentScopeMatchBy(scopeMatchBy); writer.WriteAttributeString( ProtocolStrings.SchemaNames.MatchByAttribute, string.Empty, versionDependentScopeMatchBy.GetComponents(UriComponents.SerializationInfoString, UriFormat.UriEscaped)); } if (scopes != null) { SerializationUtility.WriteListOfUris(writer, scopes); } writer.WriteEndElement(); } } public static void WriteListenUris(DiscoveryVersion discoveryVersion, Collection listenUris, XmlWriter writer) { if ((listenUris != null) && (listenUris.Count > 0)) { writer.WriteStartElement(ProtocolStrings.SchemaNames.XAddrsElement, discoveryVersion.Namespace); SerializationUtility.WriteListOfUris(writer, listenUris); writer.WriteEndElement(); } } public static void WriteMetadataVersion(DiscoveryVersion discoveryVersion, int metadataVersion, XmlWriter writer) { writer.WriteStartElement(ProtocolStrings.SchemaNames.MetadataVersionElement, discoveryVersion.Namespace); writer.WriteValue(metadataVersion); writer.WriteEndElement(); } } }