/// <summary>
        /// Parse the DigestMethod tag
        /// </summary>
        /// <param name="reader"></param>
        private static string ParseDigestAlgorithmTag(XmlReader reader)
        {
            // verify namespace and lack of attributes
            if (PackagingUtilities.GetNonXmlnsAttributeCount(reader) > 1 ||
                String.CompareOrdinal(reader.NamespaceURI, SignedXml.XmlDsigNamespaceUrl) != 0 ||
                reader.Depth != 3)
            {
                throw new XmlException(SR.Get(SRID.XmlSignatureParseError));
            }

            // get the Algorithm attribute
            string hashAlgorithm = null;

            if (reader.HasAttributes)
            {
                hashAlgorithm = reader.GetAttribute(XTable.Get(XTable.ID.AlgorithmAttrName));
            }

            if (hashAlgorithm == null || hashAlgorithm.Length == 0)
            {
                throw new XmlException(SR.Get(SRID.UnsupportedHashAlgorithm));
            }

            return(hashAlgorithm);
        }
        /// <summary>
        /// Parse the Relationship-specific Transform
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="partUri"></param>
        /// <param name="relationshipSelectors">may be allocated but will never be empty</param>
        private static void ParseRelationshipsTransform(XmlReader reader, Uri partUri, ref List <PackageRelationshipSelector> relationshipSelectors)
        {
            Uri owningPartUri = PackUriHelper.GetSourcePartUriFromRelationshipPartUri(partUri);

            // find all of the Relationship tags of form:
            //      <RelationshipReference SourceId="abc123" />
            // or
            //      <RelationshipsGroupReference SourceType="reference-type-of-the-week" />
            while (reader.Read() && (reader.MoveToContent() == XmlNodeType.Element) &&
                   reader.Depth == 5)
            {
                // both types have no children, a single required attribute and belong to the OPC namespace
                if (reader.IsEmptyElement &&
                    PackagingUtilities.GetNonXmlnsAttributeCount(reader) == 1 &&
                    (String.CompareOrdinal(reader.NamespaceURI, XTable.Get(XTable.ID.OpcSignatureNamespace)) == 0))
                {
                    // <RelationshipReference>?
                    if (String.CompareOrdinal(reader.LocalName, XTable.Get(XTable.ID.RelationshipReferenceTagName)) == 0)
                    {
                        // RelationshipReference tags are legal and these must be empty with a single SourceId attribute
                        // get the SourceId attribute
                        string id = reader.GetAttribute(XTable.Get(XTable.ID.SourceIdAttrName));
                        if (id != null && id.Length > 0)
                        {
                            if (relationshipSelectors == null)
                            {
                                relationshipSelectors = new List <PackageRelationshipSelector>();
                            }

                            // we found a legal SourceId so create a selector and continue searching
                            relationshipSelectors.Add(new PackageRelationshipSelector(owningPartUri, PackageRelationshipSelectorType.Id, id));
                            continue;
                        }
                    }   // <RelationshipsGroupReference>?
                    else if ((String.CompareOrdinal(reader.LocalName, XTable.Get(XTable.ID.RelationshipsGroupReferenceTagName)) == 0))
                    {
                        // RelationshipsGroupReference tags must be empty with a single SourceType attribute
                        string type = reader.GetAttribute(XTable.Get(XTable.ID.SourceTypeAttrName));
                        if (type != null && type.Length > 0)
                        {
                            // lazy init
                            if (relationshipSelectors == null)
                            {
                                relationshipSelectors = new List <PackageRelationshipSelector>();
                            }

                            // got a legal SourceType attribute
                            relationshipSelectors.Add(new PackageRelationshipSelector(owningPartUri, PackageRelationshipSelectorType.Type, type));
                            continue;
                        }
                    }
                }

                // if we get to here, we have not found a legal tag so we throw
                throw new XmlException(SR.Get(SRID.UnexpectedXmlTag, reader.LocalName));
            }
        }
        /// <summary>
        /// Parse the DigestValue tag
        /// </summary>
        /// <param name="reader"></param>
        private static string ParseDigestValueTag(XmlReader reader)
        {
            Debug.Assert(reader != null);

            // verify namespace and lack of attributes
            if (PackagingUtilities.GetNonXmlnsAttributeCount(reader) > 0 ||
                String.CompareOrdinal(reader.NamespaceURI, SignedXml.XmlDsigNamespaceUrl) != 0 ||
                reader.Depth != 3)
            {
                throw new XmlException(SR.Get(SRID.XmlSignatureParseError));
            }

            // there are no legal attributes and the only content must be text
            if (reader.HasAttributes || (reader.Read() && reader.MoveToContent() != XmlNodeType.Text))
            {
                throw new XmlException(SR.Get(SRID.XmlSignatureParseError));
            }

            // get the Value
            return(reader.ReadString());
        }
        /// <summary>
        /// Get the part uri and it's content type from the current Reference tag
        /// </summary>
        /// <param name="reader"></param>
        /// <param name="contentType">contentType extracted from the query portion of the Uri</param>
        /// <returns>PackagePart uri and contentType</returns>
        private static Uri ParsePartUri(XmlReader reader, out ContentType contentType)
        {
            // should be a relative Package uri with a query portion that contains the ContentType
            contentType = ContentType.Empty;
            Uri partUri = null;

            // must be one and only one attribute
            if (PackagingUtilities.GetNonXmlnsAttributeCount(reader) == 1)
            {
                string uriAttrValue = reader.GetAttribute(XTable.Get(XTable.ID.UriAttrName));
                if (uriAttrValue != null)
                {
                    partUri = ParsePartUriAttribute(uriAttrValue, out contentType);
                }
            }

            // will be null if we had no success
            if (partUri == null)
            {
                throw new XmlException(SR.Get(SRID.RequiredXmlAttributeMissing, XTable.Get(XTable.ID.UriAttrName)));
            }

            return(partUri);
        }
示例#5
0
        // Deserialize properties part.
        private void ParseCorePropertyPart(PackagePart part)
        {
            Stream stream = part.GetStream(FileMode.Open, FileAccess.Read);

            // Create a reader that uses _nameTable so as to use the set of tag literals
            // in effect as a set of atomic identifiers.
            XmlTextReader reader = new XmlTextReader(stream, _nameTable);

            //Prohibit DTD from the markup as per the OPC spec
            reader.ProhibitDtd = true;

            //This method expects the reader to be in ReadState.Initial.
            //It will make the first read call.
            PackagingUtilities.PerformInitailReadAndVerifyEncoding(reader);

            //Note: After the previous method call the reader should be at the first tag in the markup.
            //MoveToContent - Skips over the following - ProcessingInstruction, DocumentType, Comment, Whitespace, or SignificantWhitespace
            //If the reader is currently at a content node then this function call is a no-op
            if (reader.MoveToContent() != XmlNodeType.Element ||
                (object)reader.NamespaceURI != PackageXmlStringTable.GetXmlStringAsObject(PackageXmlEnum.PackageCorePropertiesNamespace) ||
                (object)reader.LocalName != PackageXmlStringTable.GetXmlStringAsObject(PackageXmlEnum.CoreProperties))
            {
                throw new XmlException(SR.Get(SRID.CorePropertiesElementExpected),
                                       null, reader.LineNumber, reader.LinePosition);
            }

            // The schema is closed and defines no attributes on the root element.
            if (PackagingUtilities.GetNonXmlnsAttributeCount(reader) != 0)
            {
                throw new XmlException(SR.Get(SRID.PropertyWrongNumbOfAttribsDefinedOn, reader.Name),
                                       null, reader.LineNumber, reader.LinePosition);
            }

            // Iterate through property elements until EOF. Note the proper closing of all
            // open tags is checked by the reader itself.
            // This loop deals only with depth-1 start tags. Handling of element content
            // is delegated to dedicated functions.
            int attributesCount;

            while (reader.Read() && reader.MoveToContent() != XmlNodeType.None)
            {
                // Ignore end-tags. We check element errors on opening tags.
                if (reader.NodeType == XmlNodeType.EndElement)
                {
                    continue;
                }

                // Any content markup that is not an element here is unexpected.
                if (reader.NodeType != XmlNodeType.Element)
                {
                    throw new XmlException(SR.Get(SRID.PropertyStartTagExpected),
                                           null, reader.LineNumber, reader.LinePosition);
                }

                // Any element below the root should open at level 1 exclusively.
                if (reader.Depth != 1)
                {
                    throw new XmlException(SR.Get(SRID.NoStructuredContentInsideProperties),
                                           null, reader.LineNumber, reader.LinePosition);
                }

                attributesCount = PackagingUtilities.GetNonXmlnsAttributeCount(reader);

                // Property elements can occur in any order (xsd:all).
                object         localName      = reader.LocalName;
                PackageXmlEnum xmlStringIndex = PackageXmlStringTable.GetEnumOf(localName);
                String         valueType      = PackageXmlStringTable.GetValueType(xmlStringIndex);

                if (Array.IndexOf(_validProperties, xmlStringIndex) == -1)  // An unexpected element is an error.
                {
                    throw new XmlException(
                              SR.Get(SRID.InvalidPropertyNameInCorePropertiesPart, reader.LocalName),
                              null, reader.LineNumber, reader.LinePosition);
                }

                // Any element not in the valid core properties namespace is unexpected.
                // The following is an object comparison, not a string comparison.
                if ((object)reader.NamespaceURI != PackageXmlStringTable.GetXmlStringAsObject(PackageXmlStringTable.GetXmlNamespace(xmlStringIndex)))
                {
                    throw new XmlException(SR.Get(SRID.UnknownNamespaceInCorePropertiesPart),
                                           null, reader.LineNumber, reader.LinePosition);
                }

                if (String.CompareOrdinal(valueType, "String") == 0)
                {
                    // The schema is closed and defines no attributes on this type of element.
                    if (attributesCount != 0)
                    {
                        throw new XmlException(SR.Get(SRID.PropertyWrongNumbOfAttribsDefinedOn, reader.Name),
                                               null, reader.LineNumber, reader.LinePosition);
                    }

                    RecordNewBinding(xmlStringIndex, GetStringData(reader), true /*initializing*/, reader);
                }
                else if (String.CompareOrdinal(valueType, "DateTime") == 0)
                {
                    int allowedAttributeCount = (object)reader.NamespaceURI ==
                                                PackageXmlStringTable.GetXmlStringAsObject(PackageXmlEnum.DublinCoreTermsNamespace)
                                                    ? 1 : 0;

                    // The schema is closed and defines no attributes on this type of element.
                    if (attributesCount != allowedAttributeCount)
                    {
                        throw new XmlException(SR.Get(SRID.PropertyWrongNumbOfAttribsDefinedOn, reader.Name),
                                               null, reader.LineNumber, reader.LinePosition);
                    }

                    if (allowedAttributeCount != 0)
                    {
                        ValidateXsiType(reader,
                                        PackageXmlStringTable.GetXmlStringAsObject(PackageXmlEnum.DublinCoreTermsNamespace),
                                        _w3cdtf);
                    }

                    RecordNewBinding(xmlStringIndex, GetDateData(reader), true /*initializing*/, reader);
                }
                else  // An unexpected element is an error.
                {
                    Invariant.Assert(false, "Unknown value type for properties");
                }
            }
        }
        /// <summary>
        /// Parses Transforms tag
        /// </summary>
        /// <param name="reader">node to parse</param>
        /// <param name="partUri">Part Uri for the part owning the relationships</param>
        /// <param name="relationshipSelectors">allocates and returns a list of
        /// PackageRelationshipSelectors if Relationship transform</param>
        /// <returns>ordered list of Transform names</returns>
        private static List <String> ParseTransformsTag(XmlReader reader, Uri partUri, ref List <PackageRelationshipSelector> relationshipSelectors)
        {
            // # reference that signs multiple PackageRelationships
            // <Reference URI="/shared/_rels/image.jpg.rels?ContentType=image/jpg">
            //      <Transforms>
            //          <Transform Algorithm="http://schemas.openxmlformats.org/package/2006/RelationshipTransform">
            //              <RelationshipReference SourceId="1" />
            //              <RelationshipReference SourceId="2" />
            //              <RelationshipReference SourceId="8" />
            //          </Transform>
            //          <Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
            //      </Transforms>
            //      <DigestMethod Algorithm="sha1" />
            //      <DigestValue>... </DigestValue>
            // </Reference>

            // verify lack of attributes
            if (PackagingUtilities.GetNonXmlnsAttributeCount(reader) != 0)
            {
                throw new XmlException(SR.Get(SRID.XmlSignatureParseError));
            }

            List <String> transforms = null;
            bool          relationshipTransformFound = false;
            int           transformsCountWhenRelationshipTransformFound = 0;

            // Look for transforms.
            // There are currently only 3 legal transforms which can be arranged in any
            // combination.
            while (reader.Read() && (reader.MoveToContent() == XmlNodeType.Element))
            {
                String transformName = null;

                // at this level, all tags must be Transform tags
                if (reader.Depth != 4 ||
                    String.CompareOrdinal(reader.NamespaceURI, SignedXml.XmlDsigNamespaceUrl) != 0 ||
                    String.CompareOrdinal(reader.LocalName, XTable.Get(XTable.ID.TransformTagName)) != 0)
                {
                    throw new XmlException(SR.Get(SRID.XmlSignatureParseError));
                }

                // inspect the Algorithm attribute to determine the type of transform
                if (PackagingUtilities.GetNonXmlnsAttributeCount(reader) == 1)
                {
                    transformName = reader.GetAttribute(XTable.Get(XTable.ID.AlgorithmAttrName));
                }

                // legal transform name?
                if ((transformName != null) && (transformName.Length > 0))
                {
                    // what type of transform?
                    if (String.CompareOrdinal(transformName, XTable.Get(XTable.ID.RelationshipsTransformName)) == 0)
                    {
                        if (!relationshipTransformFound)
                        {
                            // relationship transform
                            ParseRelationshipsTransform(reader, partUri, ref relationshipSelectors);

                            if (transforms == null)
                            {
                                transforms = new List <String>();
                            }

                            transforms.Add(transformName);

                            relationshipTransformFound = true;
                            transformsCountWhenRelationshipTransformFound = transforms.Count;
                            continue;   // success
                        }
                        else
                        {
                            throw new XmlException(SR.Get(SRID.MultipleRelationshipTransformsFound));
                        }
                    }
                    else
                    {
                        // non-Relationship transform should have no children
                        if (reader.IsEmptyElement)
                        {
                            if (transforms == null)
                            {
                                transforms = new List <String>();
                            }

                            if (XmlDigitalSignatureProcessor.IsValidXmlCanonicalizationTransform(transformName))
                            {
                                transforms.Add(transformName); // return it
                                continue;                      // success
                            }
                            else
                            {
                                throw new InvalidOperationException(SR.Get(SRID.UnsupportedTransformAlgorithm));
                            }
                        }
                    }
                }
                throw new XmlException(SR.Get(SRID.XmlSignatureParseError));
            }

            if (transforms.Count == 0)
            {
                throw new XmlException(SR.Get(SRID.XmlSignatureParseError));
            }

            //If we found another transform after the Relationship transform, it will be validated earlier
            //in this method to make sure that its a supported xml canonicalization algorithm and so we can
            //simplify this test condition - As per the OPC spec - Relationship transform must be followed
            //by a canonicalization algorithm.
            if (relationshipTransformFound && (transforms.Count == transformsCountWhenRelationshipTransformFound))
            {
                throw new XmlException(SR.Get(SRID.RelationshipTransformNotFollowedByCanonicalizationTransform));
            }

            return(transforms);
        }
示例#7
0
        //-----------------------------------------------------------------------------
        //
        // Private Methods
        //
        //-----------------------------------------------------------------------------

        /// <summary>
        /// Parse the SignatureTime tag
        /// </summary>
        /// <param name="reader">NodeReader positioned at the SignatureProperty tag</param>
        /// <param name="timeFormat">format found</param>
        /// <exception cref="XmlException">illegal format</exception>
        /// <returns>signing time</returns>
        private static DateTime ParseSignatureTimeTag(XmlReader reader, out String timeFormat)
        {
            //There are no attributes on all the three tags that we parse in this method
            //<SignatureTime>, <Format>, <Value>
            int expectedAttributeCount = 0;

            string opcSignatureNameSpace = XTable.Get(XTable.ID.OpcSignatureNamespace);
            string signaturePropertyTag  = XTable.Get(XTable.ID.SignaturePropertyTagName);
            string signatureTimeTag      = XTable.Get(XTable.ID.SignatureTimeTagName);
            string timeValueTagName      = XTable.Get(XTable.ID.SignatureTimeValueTagName);
            string timeFormatTagName     = XTable.Get(XTable.ID.SignatureTimeFormatTagName);

            // <SignatureTime> must be one of <Format> or <Time>
            timeFormat = null;
            string timeValue = null;

            //Look for <SignatureTime> Tag
            if (reader.Read() &&
                reader.MoveToContent() == XmlNodeType.Element &&
                (String.CompareOrdinal(reader.NamespaceURI, opcSignatureNameSpace) == 0) &&
                (String.CompareOrdinal(reader.LocalName, signatureTimeTag) == 0) &&
                reader.Depth == 3 &&
                PackagingUtilities.GetNonXmlnsAttributeCount(reader) == expectedAttributeCount)
            {
                while (reader.Read())
                {
                    if (String.CompareOrdinal(reader.NamespaceURI, opcSignatureNameSpace) == 0 &&
                        reader.MoveToContent() == XmlNodeType.Element &&
                        reader.Depth == 4)
                    {
                        // which tag do we have?
                        if ((String.CompareOrdinal(reader.LocalName, timeValueTagName) == 0) &&
                            PackagingUtilities.GetNonXmlnsAttributeCount(reader) == expectedAttributeCount)
                        {
                            if (timeValue == null &&
                                reader.Read() &&
                                reader.MoveToContent() == XmlNodeType.Text &&
                                reader.Depth == 5)
                            {
                                //After reading the content, the reader progresses to the next element.
                                //So after this method is called, the reader is positioned at the
                                //EndElement corresponding to Value tag - </Value>
                                // Note: ReadContentAsString will return String.Empty but never null
                                timeValue = reader.ReadContentAsString();
                                Debug.Assert(reader.NodeType == XmlNodeType.EndElement);
                            }
                            else
                            {
                                //This would happen if we found more than one Value tags or if there
                                //are other nested elements of if they are of a different XmlNodeType type
                                throw new XmlException(SR.PackageSignatureCorruption);
                            }
                        }
                        else if ((String.CompareOrdinal(reader.LocalName, timeFormatTagName) == 0) &&
                                 PackagingUtilities.GetNonXmlnsAttributeCount(reader) == expectedAttributeCount)
                        {
                            if (timeFormat == null &&
                                reader.Read() &&
                                reader.MoveToContent() == XmlNodeType.Text &&
                                reader.Depth == 5)
                            {
                                //After reading the content, the reader progresses to the next element.
                                //So after this method is called, the reader is positioned at the
                                //EndElement corresponding to Format tag - </Format>
                                // Note: ReadContentAsString will return String.Empty but never null
                                timeFormat = reader.ReadContentAsString();
                                Debug.Assert(reader.NodeType == XmlNodeType.EndElement);
                            }
                            else
                            {
                                //This would happen if we found more than one Format tags or if there
                                //are other nested elements of if they are of a different XmlNodeType type
                                throw new XmlException(SR.PackageSignatureCorruption);
                            }
                        }
                        else
                        {
                            //If we encounter any tag other than <Format> or <Time> nested within the <SignatureTime> tag
                            throw new XmlException(SR.PackageSignatureCorruption);
                        }
                    }
                    else
                    //If we have encountered the end tag for the <SignatureTime> tag
                    //then we are done parsing the tag, and we can stop the parsing.
                    if (String.CompareOrdinal(signatureTimeTag, reader.LocalName) == 0 &&
                        (reader.NodeType == XmlNodeType.EndElement))
                    {
                        //We must find a  </SignatureProperty> tag at this point,
                        //else it could be that there are more SignatureTime or
                        //other tags nested here and that is an error.
                        if (reader.Read() &&
                            reader.MoveToContent() == XmlNodeType.EndElement &&
                            String.CompareOrdinal(signaturePropertyTag, reader.LocalName) == 0)
                        {
                            break;
                        }
                        else
                        {
                            throw new XmlException(SR.PackageSignatureCorruption);
                        }
                    }
                    else
                    {
                        // if we do not find the nested elements as expected
                        throw new XmlException(SR.PackageSignatureCorruption);
                    }
                }
            }
            else
            {
                throw new XmlException(SR.Format(SR.RequiredTagNotFound, signatureTimeTag));
            }


            // generate an equivalent DateTime object
            if (timeValue != null && timeFormat != null)
            {
                return(XmlFormattedTimeToDateTime(timeValue, timeFormat));
            }
            else
            {
                throw new XmlException(SR.PackageSignatureCorruption);
            }
        }
示例#8
0
        /// <summary>
        /// Parse PackageRelationship Stream
        /// </summary>
        /// <param name="part">relationship part</param>
        /// <exception cref="XmlException">Thrown if XML is malformed</exception>
        private void ParseRelationshipPart(PackagePart part)
        {
            //We can safely open the stream as FileAccess.Read, as this code
            //should only be invoked if the Package has been opened in Read or ReadWrite mode.
            Debug.Assert(_package.FileOpenAccess == FileAccess.Read || _package.FileOpenAccess == FileAccess.ReadWrite,
                         "This method should only be called when FileAccess is Read or ReadWrite");

            using (Stream s = part.GetStream(FileMode.Open, FileAccess.Read))
            {
                // load from the relationship part associated with the given part
                using (XmlTextReader baseReader = new XmlTextReader(s))
                {
                    baseReader.WhitespaceHandling = WhitespaceHandling.None;

                    //Prohibit DTD from the markup as per the OPC spec
                    baseReader.ProhibitDtd = true;

                    using (XmlCompatibilityReader reader = new XmlCompatibilityReader(baseReader, RelationshipKnownNamespaces))
                    {
                        //This method expects the reader to be in ReadState.Initial.
                        //It will make the first read call.
                        PackagingUtilities.PerformInitailReadAndVerifyEncoding(baseReader);

                        //Note: After the previous method call the reader should be at the first tag in the markup.
                        //MoveToContent - Skips over the following - ProcessingInstruction, DocumentType, Comment, Whitespace, or SignificantWhitespace
                        //If the reader is currently at a content node then this function call is a no-op
                        reader.MoveToContent();

                        // look for our tag and namespace pair - throw if other elements are encountered
                        // Make sure that the current node read is an Element
                        if (reader.NodeType == XmlNodeType.Element &&
                            (reader.Depth == 0) &&
                            (String.CompareOrdinal(RelationshipsTagName, reader.LocalName) == 0) &&
                            (String.CompareOrdinal(PackagingUtilities.RelationshipNamespaceUri, reader.NamespaceURI) == 0))
                        {
                            ThrowIfXmlBaseAttributeIsPresent(reader);

                            //There should be a namespace Attribute present at this level.
                            //Also any other attribute on the <Relationships> tag is an error including xml: and xsi: attributes
                            if (PackagingUtilities.GetNonXmlnsAttributeCount(reader) > 0)
                            {
                                throw new XmlException(SR.Get(SRID.RelationshipsTagHasExtraAttributes), null, reader.LineNumber, reader.LinePosition);
                            }

                            // start tag encountered for Relationships
                            // now parse individual Relationship tags
                            while (reader.Read())
                            {
                                //Skips over the following - ProcessingInstruction, DocumentType, Comment, Whitespace, or SignificantWhitespace
                                //If the reader is currently at a content node then this function call is a no-op
                                reader.MoveToContent();

                                //If MoveToContent() takes us to the end of the content
                                if (reader.NodeType == XmlNodeType.None)
                                {
                                    continue;
                                }

                                if (reader.NodeType == XmlNodeType.Element &&
                                    (reader.Depth == 1) &&
                                    (String.CompareOrdinal(RelationshipTagName, reader.LocalName) == 0) &&
                                    (String.CompareOrdinal(PackagingUtilities.RelationshipNamespaceUri, reader.NamespaceURI) == 0))
                                {
                                    ThrowIfXmlBaseAttributeIsPresent(reader);

                                    int expectedAttributesCount = 3;

                                    string targetModeAttributeValue = reader.GetAttribute(TargetModeAttributeName);
                                    if (targetModeAttributeValue != null)
                                    {
                                        expectedAttributesCount++;
                                    }

                                    //check if there are expected number of attributes.
                                    //Also any other attribute on the <Relationship> tag is an error including xml: and xsi: attributes
                                    if (PackagingUtilities.GetNonXmlnsAttributeCount(reader) == expectedAttributesCount)
                                    {
                                        ProcessRelationshipAttributes(reader);

                                        //Skip the EndElement for Relationship
                                        if (!reader.IsEmptyElement)
                                        {
                                            ProcessEndElementForRelationshipTag(reader);
                                        }
                                    }
                                    else
                                    {
                                        throw new XmlException(SR.Get(SRID.RelationshipTagDoesntMatchSchema), null, reader.LineNumber, reader.LinePosition);
                                    }
                                }
                                else
                                if (!(String.CompareOrdinal(RelationshipsTagName, reader.LocalName) == 0 && (reader.NodeType == XmlNodeType.EndElement)))
                                {
                                    throw new XmlException(SR.Get(SRID.UnknownTagEncountered), null, reader.LineNumber, reader.LinePosition);
                                }
                            }
                        }
                        else
                        {
                            throw new XmlException(SR.Get(SRID.ExpectedRelationshipsElementTag), null, reader.LineNumber, reader.LinePosition);
                        }
                    }
                }
            }
        }