You've already forked linux-packaging-mono
							
							
		
			
				
	
	
		
			419 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			419 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| 
 | |
| //------------------------------------------------------------------------------
 | |
| // <copyright file="Parser.cs" company="Microsoft">
 | |
| //     Copyright (c) Microsoft Corporation.  All rights reserved.
 | |
| // </copyright>  
 | |
| // <owner current="true" primary="true">Microsoft</owner>                                                              
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| namespace System.Xml.Schema {
 | |
| 
 | |
|     using System;
 | |
|     using System.Collections;
 | |
|     using System.Globalization;
 | |
|     using System.Text;
 | |
|     using System.IO;
 | |
|     using System.Diagnostics;
 | |
| 
 | |
|     internal sealed partial class Parser {
 | |
| 
 | |
|         SchemaType schemaType;
 | |
|         XmlNameTable nameTable;
 | |
|         SchemaNames schemaNames; 
 | |
|         ValidationEventHandler eventHandler;
 | |
|         XmlNamespaceManager namespaceManager;
 | |
|         XmlReader reader;
 | |
|         PositionInfo positionInfo;
 | |
|         bool isProcessNamespaces;
 | |
|         int schemaXmlDepth = 0;
 | |
|         int markupDepth;
 | |
|         SchemaBuilder builder;
 | |
|         XmlSchema schema;
 | |
|         SchemaInfo xdrSchema;
 | |
|         XmlResolver xmlResolver = null; //to be used only by XDRBuilder
 | |
| 
 | |
|         //xs:Annotation perf fix
 | |
|         XmlDocument dummyDocument;
 | |
|         bool processMarkup;
 | |
|         XmlNode parentNode;
 | |
|         XmlNamespaceManager annotationNSManager;
 | |
|         string xmlns;
 | |
| 
 | |
|         //Whitespace check for text nodes
 | |
|         XmlCharType xmlCharType = XmlCharType.Instance;
 | |
| 
 | |
|         public Parser(SchemaType schemaType, XmlNameTable nameTable, SchemaNames schemaNames, ValidationEventHandler eventHandler) {
 | |
|             this.schemaType = schemaType;
 | |
|             this.nameTable = nameTable;
 | |
|             this.schemaNames = schemaNames;
 | |
|             this.eventHandler = eventHandler;
 | |
|             this.xmlResolver = System.Xml.XmlConfiguration.XmlReaderSection.CreateDefaultResolver();
 | |
|             processMarkup = true;
 | |
|             dummyDocument = new XmlDocument();
 | |
|         }
 | |
| 
 | |
|         public  SchemaType  Parse(XmlReader reader, string targetNamespace) {
 | |
|             StartParsing(reader, targetNamespace);
 | |
|             while(ParseReaderNode() && reader.Read()) {}
 | |
|             return FinishParsing();
 | |
|         }
 | |
| 
 | |
|         public void StartParsing(XmlReader reader, string targetNamespace) {
 | |
|             this.reader = reader;
 | |
|             positionInfo = PositionInfo.GetPositionInfo(reader);
 | |
|             namespaceManager = reader.NamespaceManager;
 | |
|             if (namespaceManager == null) {
 | |
|                 namespaceManager = new XmlNamespaceManager(nameTable);
 | |
|                 isProcessNamespaces = true;
 | |
|             } 
 | |
|             else {
 | |
|                 isProcessNamespaces = false;
 | |
|             }
 | |
|             while (reader.NodeType != XmlNodeType.Element && reader.Read()) {}
 | |
| 
 | |
|             markupDepth = int.MaxValue;
 | |
|             schemaXmlDepth = reader.Depth;
 | |
|             SchemaType rootType = schemaNames.SchemaTypeFromRoot(reader.LocalName, reader.NamespaceURI);
 | |
|             
 | |
|             string code;
 | |
|             if (!CheckSchemaRoot(rootType, out code)) {
 | |
|                 throw new XmlSchemaException(code, reader.BaseURI, positionInfo.LineNumber, positionInfo.LinePosition);
 | |
|             }
 | |
|             
 | |
|             if (schemaType == SchemaType.XSD) {
 | |
|                 schema = new XmlSchema();
 | |
|                 schema.BaseUri = new Uri(reader.BaseURI, UriKind.RelativeOrAbsolute);
 | |
|                 builder = new XsdBuilder(reader, namespaceManager, schema, nameTable, schemaNames, eventHandler);
 | |
|             }
 | |
|             else {  
 | |
|                 Debug.Assert(schemaType == SchemaType.XDR);
 | |
|                 xdrSchema = new SchemaInfo();
 | |
|                 xdrSchema.SchemaType = SchemaType.XDR;
 | |
|                 builder = new XdrBuilder(reader, namespaceManager, xdrSchema, targetNamespace, nameTable, schemaNames, eventHandler);
 | |
|                 ((XdrBuilder)builder).XmlResolver = xmlResolver;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private bool CheckSchemaRoot(SchemaType rootType, out string code) {
 | |
|             code = null;
 | |
|             if (schemaType == SchemaType.None) {
 | |
|                 schemaType = rootType;
 | |
|             }
 | |
|             switch (rootType) {
 | |
|                 case SchemaType.XSD:
 | |
|                     if (schemaType != SchemaType.XSD) {
 | |
|                         code = Res.Sch_MixSchemaTypes;
 | |
|                         return false;
 | |
|                     }
 | |
|                 break;
 | |
| 
 | |
|                 case SchemaType.XDR:
 | |
|                     if (schemaType == SchemaType.XSD) {
 | |
|                         code = Res.Sch_XSDSchemaOnly;
 | |
|                         return false;
 | |
|                     }
 | |
|                     else if (schemaType != SchemaType.XDR) {
 | |
|                         code = Res.Sch_MixSchemaTypes;
 | |
|                         return false;
 | |
|                     }
 | |
|                 break;
 | |
|         
 | |
|                 case SchemaType.DTD: //Did not detect schema type that can be parsed by this parser
 | |
|                 case SchemaType.None:
 | |
|                     code = Res.Sch_SchemaRootExpected;
 | |
|                     if (schemaType == SchemaType.XSD) {
 | |
|                         code = Res.Sch_XSDSchemaRootExpected;
 | |
|                     }
 | |
|                     return false;
 | |
|     
 | |
|                 default:
 | |
|                     Debug.Assert(false);
 | |
|                     break;
 | |
|             }
 | |
|             return true;
 | |
|         }
 | |
| 
 | |
|         public SchemaType FinishParsing() {
 | |
|             return schemaType;
 | |
|         }
 | |
| 
 | |
|         public XmlSchema XmlSchema {
 | |
|             get { return schema; }
 | |
|         }
 | |
| 
 | |
|         internal XmlResolver XmlResolver {
 | |
|             set {
 | |
|                 xmlResolver = value;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         public SchemaInfo XdrSchema {
 | |
|             get { return xdrSchema; }
 | |
|         }
 | |
| 
 | |
|         public bool ParseReaderNode() {
 | |
|             if (reader.Depth > markupDepth) {
 | |
|                 if (processMarkup) {
 | |
|                     ProcessAppInfoDocMarkup(false);
 | |
|                 }
 | |
|                 return true;
 | |
|             }
 | |
|             else if (reader.NodeType == XmlNodeType.Element) {
 | |
|                 if (builder.ProcessElement(reader.Prefix, reader.LocalName, reader.NamespaceURI)) {
 | |
|                     namespaceManager.PushScope();
 | |
|                     if (reader.MoveToFirstAttribute()) {
 | |
|                         do {
 | |
|                             builder.ProcessAttribute(reader.Prefix, reader.LocalName, reader.NamespaceURI, reader.Value);
 | |
|                             if (Ref.Equal(reader.NamespaceURI, schemaNames.NsXmlNs) && isProcessNamespaces) {                        
 | |
|                                 namespaceManager.AddNamespace(reader.Prefix.Length == 0 ? string.Empty : reader.LocalName, reader.Value);
 | |
|                             }
 | |
|                         }
 | |
|                         while (reader.MoveToNextAttribute());
 | |
|                         reader.MoveToElement(); // get back to the element
 | |
|                     }
 | |
|                     builder.StartChildren();
 | |
|                     if (reader.IsEmptyElement) {
 | |
|                         namespaceManager.PopScope();
 | |
|                         builder.EndChildren();
 | |
|                         if (reader.Depth == schemaXmlDepth) {
 | |
|                             return false; // done
 | |
|                         }
 | |
|                     } 
 | |
|                     else if (!builder.IsContentParsed()) { //AppInfo and Documentation
 | |
|                         markupDepth = reader.Depth;
 | |
|                         processMarkup = true;
 | |
|                         if (annotationNSManager == null) {
 | |
|                             annotationNSManager = new XmlNamespaceManager(nameTable);
 | |
|                             xmlns = nameTable.Add("xmlns");
 | |
|                         }
 | |
|                         ProcessAppInfoDocMarkup(true);
 | |
|                     }
 | |
|                 } 
 | |
|                 else if (!reader.IsEmptyElement) { //UnsupportedElement in that context
 | |
|                     markupDepth = reader.Depth;
 | |
|                     processMarkup = false; //Hack to not process unsupported elements
 | |
|                 }
 | |
|             } 
 | |
|             else if (reader.NodeType == XmlNodeType.Text) { //Check for whitespace
 | |
|                 if (!xmlCharType.IsOnlyWhitespace(reader.Value)) {
 | |
|                     builder.ProcessCData(reader.Value);
 | |
|                 }
 | |
|             }
 | |
|             else if (reader.NodeType == XmlNodeType.EntityReference ||
 | |
|                 reader.NodeType == XmlNodeType.SignificantWhitespace ||
 | |
|                 reader.NodeType == XmlNodeType.CDATA) {
 | |
|                 builder.ProcessCData(reader.Value);
 | |
|             }
 | |
|             else if (reader.NodeType == XmlNodeType.EndElement) {
 | |
| 
 | |
|                 if (reader.Depth == markupDepth) {
 | |
|                     if (processMarkup) {
 | |
|                         Debug.Assert(parentNode != null);
 | |
|                         XmlNodeList list = parentNode.ChildNodes;
 | |
|                         XmlNode[] markup = new XmlNode[list.Count];
 | |
|                         for (int i = 0; i < list.Count; i ++) {
 | |
|                             markup[i] = list[i];
 | |
|                         }
 | |
|                         builder.ProcessMarkup(markup);
 | |
|                         namespaceManager.PopScope();
 | |
|                         builder.EndChildren();
 | |
|                     }
 | |
|                     markupDepth = int.MaxValue;
 | |
|                 } 
 | |
|                 else {
 | |
|                     namespaceManager.PopScope();
 | |
|                     builder.EndChildren();
 | |
|                 }
 | |
|                 if(reader.Depth == schemaXmlDepth) {
 | |
|                     return false; // done
 | |
|                 }
 | |
|             }
 | |
|             return true;
 | |
|         }
 | |
|         
 | |
|         private void ProcessAppInfoDocMarkup(bool root) {
 | |
|             //First time reader is positioned on AppInfo or Documentation element
 | |
|             XmlNode currentNode = null; 
 | |
|             
 | |
|             switch (reader.NodeType) {
 | |
|                 case XmlNodeType.Element:
 | |
|                     annotationNSManager.PushScope();
 | |
|                     currentNode = LoadElementNode(root);
 | |
|                     //  Dev10 (TFS) #479761: The following code was to address the issue of where an in-scope namespace delaration attribute
 | |
|                     //      was not added when an element follows an empty element. This fix will result in persisting schema in a consistent form
 | |
|                     //      although it does not change the semantic meaning of the schema.
 | |
|                     //      Since it is as a breaking change and Dev10 needs to maintain the backward compatibility, this fix is being reverted.
 | |
|                     //  if (reader.IsEmptyElement) {
 | |
|                     //      annotationNSManager.PopScope();
 | |
|                     //  }
 | |
|                     break;
 | |
|                 
 | |
|                 case XmlNodeType.Text:
 | |
|                     currentNode = dummyDocument.CreateTextNode( reader.Value );
 | |
|                     goto default;
 | |
| 
 | |
|                 case XmlNodeType.SignificantWhitespace:
 | |
|                     currentNode = dummyDocument.CreateSignificantWhitespace( reader.Value );
 | |
|                     goto default;
 | |
| 
 | |
|                 case XmlNodeType.CDATA:
 | |
|                     currentNode = dummyDocument.CreateCDataSection( reader.Value );
 | |
|                     goto default;
 | |
| 
 | |
|                 case XmlNodeType.EntityReference:
 | |
|                     currentNode = dummyDocument.CreateEntityReference( reader.Name );
 | |
|                     goto default;
 | |
| 
 | |
|                 case XmlNodeType.Comment:    
 | |
|                     currentNode = dummyDocument.CreateComment( reader.Value );
 | |
|                     goto default;
 | |
| 
 | |
|                 case XmlNodeType.ProcessingInstruction:
 | |
|                     currentNode = dummyDocument.CreateProcessingInstruction( reader.Name, reader.Value );
 | |
|                     goto default;
 | |
|                 
 | |
|                 case XmlNodeType.EndEntity:
 | |
|                     break;
 | |
|                 
 | |
|                 case XmlNodeType.Whitespace:
 | |
|                     break;
 | |
| 
 | |
|                 case XmlNodeType.EndElement:
 | |
|                     annotationNSManager.PopScope();
 | |
|                     parentNode = parentNode.ParentNode;
 | |
|                     break;
 | |
|                 
 | |
|                 default: //other possible node types: Document/DocType/DocumentFrag/Entity/Notation/Xmldecl cannot appear as children of xs:appInfo or xs:doc
 | |
|                     Debug.Assert(currentNode != null);
 | |
|                     Debug.Assert(parentNode != null);
 | |
|                     parentNode.AppendChild(currentNode);
 | |
|                     break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private XmlElement LoadElementNode(bool root) {
 | |
|             Debug.Assert( reader.NodeType == XmlNodeType.Element );
 | |
|             
 | |
|             XmlReader r = reader;
 | |
|             bool fEmptyElement = r.IsEmptyElement;
 | |
| 
 | |
|             XmlElement element = dummyDocument.CreateElement( r.Prefix, r.LocalName, r.NamespaceURI );
 | |
|             element.IsEmpty = fEmptyElement;
 | |
|             
 | |
|             if (root) {
 | |
|                 parentNode = element;
 | |
|             }
 | |
|             else {
 | |
|                 XmlAttributeCollection attributes = element.Attributes;
 | |
|                 if (r.MoveToFirstAttribute()) {
 | |
|                     do {
 | |
|                         if (Ref.Equal(r.NamespaceURI, schemaNames.NsXmlNs)) { //Namespace Attribute
 | |
|                             annotationNSManager.AddNamespace(r.Prefix.Length == 0 ? string.Empty : reader.LocalName, reader.Value);
 | |
|                         }
 | |
|                         XmlAttribute attr = LoadAttributeNode();
 | |
|                         attributes.Append( attr );
 | |
|                     } while(r.MoveToNextAttribute());
 | |
|                 }
 | |
|                 r.MoveToElement();
 | |
|                 string ns = annotationNSManager.LookupNamespace(r.Prefix);
 | |
|                 if (ns == null) {
 | |
|                     XmlAttribute attr = CreateXmlNsAttribute(r.Prefix, namespaceManager.LookupNamespace(r.Prefix)); 
 | |
|                     attributes.Append(attr);
 | |
|                 }
 | |
|                 else if (ns.Length == 0) { //string.Empty prefix is mapped to string.Empty NS by default
 | |
|                     string elemNS = namespaceManager.LookupNamespace(r.Prefix);
 | |
|                     if (elemNS != string.Empty) {
 | |
|                         XmlAttribute attr = CreateXmlNsAttribute(r.Prefix, elemNS); 
 | |
|                         attributes.Append(attr);
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|                 while (r.MoveToNextAttribute()) {
 | |
|                     if (r.Prefix.Length != 0) {
 | |
|                         string attNS = annotationNSManager.LookupNamespace(r.Prefix);
 | |
|                         if (attNS == null) {
 | |
|                             XmlAttribute attr = CreateXmlNsAttribute(r.Prefix, namespaceManager.LookupNamespace(r.Prefix)); 
 | |
|                             attributes.Append(attr);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 r.MoveToElement();
 | |
| 
 | |
|                 parentNode.AppendChild(element);
 | |
|                 if (!r.IsEmptyElement) {
 | |
|                     parentNode = element;
 | |
|                 }
 | |
|             }
 | |
|             return element;
 | |
|         }
 | |
|         
 | |
|         private XmlAttribute CreateXmlNsAttribute(string prefix, string value) {
 | |
|             XmlAttribute attr;
 | |
|             if (prefix.Length == 0) {
 | |
|                 attr = dummyDocument.CreateAttribute(string.Empty, xmlns, XmlReservedNs.NsXmlNs);
 | |
|             }
 | |
|             else {
 | |
|                 attr = dummyDocument.CreateAttribute(xmlns, prefix, XmlReservedNs.NsXmlNs);
 | |
|             }
 | |
|             attr.AppendChild(dummyDocument.CreateTextNode(value));
 | |
|             annotationNSManager.AddNamespace(prefix, value);
 | |
|             return attr;
 | |
|         }
 | |
| 
 | |
|         private XmlAttribute LoadAttributeNode() {
 | |
|             Debug.Assert(reader.NodeType == XmlNodeType.Attribute);
 | |
| 
 | |
|             XmlReader r = reader;
 | |
| 
 | |
|             XmlAttribute attr = dummyDocument.CreateAttribute(r.Prefix, r.LocalName, r.NamespaceURI);
 | |
| 
 | |
|             while (r.ReadAttributeValue() ) {
 | |
|                 switch (r.NodeType) {
 | |
|                     case XmlNodeType.Text:
 | |
|                         attr.AppendChild(dummyDocument.CreateTextNode(r.Value));
 | |
|                         continue;
 | |
|                     case XmlNodeType.EntityReference:
 | |
|                         attr.AppendChild(LoadEntityReferenceInAttribute());
 | |
|                         continue;
 | |
|                     default:
 | |
|                         throw XmlLoader.UnexpectedNodeType( r.NodeType );
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return attr;
 | |
|         }
 | |
| 
 | |
|         private XmlEntityReference LoadEntityReferenceInAttribute() {
 | |
|             Debug.Assert(reader.NodeType == XmlNodeType.EntityReference);
 | |
| 
 | |
|             XmlEntityReference eref = dummyDocument.CreateEntityReference( reader.LocalName );
 | |
|             if ( !reader.CanResolveEntity ) {
 | |
|                 return eref;
 | |
|             }
 | |
|             reader.ResolveEntity();
 | |
| 
 | |
|             while (reader.ReadAttributeValue()) {
 | |
|                 switch (reader.NodeType) {
 | |
|                     case XmlNodeType.Text:
 | |
|                         eref.AppendChild(dummyDocument.CreateTextNode(reader.Value));
 | |
|                         continue;
 | |
|                     case XmlNodeType.EndEntity:
 | |
|                         if ( eref.ChildNodes.Count == 0 ) {
 | |
|                             eref.AppendChild(dummyDocument.CreateTextNode(String.Empty));
 | |
|                         }
 | |
|                         return eref;
 | |
|                     case XmlNodeType.EntityReference: 
 | |
|                         eref.AppendChild(LoadEntityReferenceInAttribute());
 | |
|                         break;
 | |
|                     default:
 | |
|                         throw XmlLoader.UnexpectedNodeType( reader.NodeType );
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             return eref;
 | |
|         }
 | |
| 
 | |
|     };
 | |
| 
 | |
| } // namespace System.Xml
 |