You've already forked linux-packaging-mono
							
							
		
			
				
	
	
		
			1369 lines
		
	
	
		
			61 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			1369 lines
		
	
	
		
			61 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| //------------------------------------------------------------------------------
 | |
| // <copyright file="XmlSchemaSet.cs" company="Microsoft">
 | |
| //     Copyright (c) Microsoft Corporation.  All rights reserved.
 | |
| // </copyright>
 | |
| // <owner current="true" primary="true">Microsoft</owner>                                                                 
 | |
| //------------------------------------------------------------------------------
 | |
| using System.Diagnostics;
 | |
| using System.Collections;
 | |
| using System.Threading;
 | |
| using System.Collections.Generic;
 | |
| using System.Runtime.Versioning;
 | |
| 
 | |
| namespace System.Xml.Schema {
 | |
| #if SILVERLIGHT
 | |
|     public class XmlSchemaSet
 | |
|     {
 | |
|         //Empty XmlSchemaSet class to enable backward compatibility of XmlSchemaProvideAttribute        
 | |
|         //Add private ctor to prevent constructing of this class
 | |
|         XmlSchemaSet() { }
 | |
|     }
 | |
| #else
 | |
|     /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet"]/*' />
 | |
|     /// <devdoc>
 | |
|     ///    <para>The XmlSchemaSet contains a set of namespace URI's.
 | |
|     ///       Each namespace also have an associated private data cache
 | |
|     ///       corresponding to the XML-Data Schema or W3C XML Schema.
 | |
|     ///       The XmlSchemaSet will able to load only XSD schemas,
 | |
|     ///       and compile them into an internal "cooked schema representation".
 | |
|     ///       The Validate method then uses this internal representation for
 | |
|     ///       efficient runtime validation of any given subtree.</para>
 | |
|     /// </devdoc>
 | |
|     public class XmlSchemaSet {
 | |
|         XmlNameTable nameTable;         
 | |
|         SchemaNames schemaNames;
 | |
|         SortedList schemas;              // List of source schemas 
 | |
|         
 | |
|         //Event handling
 | |
|         ValidationEventHandler internalEventHandler;
 | |
|         ValidationEventHandler eventHandler;
 | |
| 
 | |
|         bool isCompiled = false;
 | |
| 
 | |
|         //Dictionary<Uri, XmlSchema> schemaLocations;
 | |
|         //Dictionary<ChameleonKey, XmlSchema> chameleonSchemas;
 | |
|         Hashtable schemaLocations;
 | |
|         Hashtable chameleonSchemas;
 | |
| 
 | |
|         Hashtable targetNamespaces;
 | |
|         bool compileAll;
 | |
|         
 | |
|         //Cached Compiled Info
 | |
|         SchemaInfo cachedCompiledInfo;
 | |
|         
 | |
|         //Reader settings to parse schema
 | |
|         XmlReaderSettings readerSettings;
 | |
|         XmlSchema schemaForSchema;  //Only one schema for schema per set
 | |
|      
 | |
|         //Schema compilation settings
 | |
|         XmlSchemaCompilationSettings compilationSettings;
 | |
| 
 | |
|         internal XmlSchemaObjectTable elements;
 | |
|         internal XmlSchemaObjectTable attributes;
 | |
|         internal XmlSchemaObjectTable schemaTypes;
 | |
|         internal XmlSchemaObjectTable substitutionGroups;
 | |
|         private XmlSchemaObjectTable typeExtensions;
 | |
| 
 | |
|         //Thread safety
 | |
|         private Object internalSyncObject;
 | |
|         internal Object InternalSyncObject {
 | |
|             get {
 | |
|                 if (internalSyncObject == null) {
 | |
|                     Object o = new Object();
 | |
|                     Interlocked.CompareExchange<Object>(ref internalSyncObject, o, null);
 | |
|                 }
 | |
|                 return internalSyncObject;
 | |
|             }
 | |
|         }
 | |
| 
 | |
| //Constructors
 | |
| 
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.XmlSchemaSet"]/*' />
 | |
|         /// <devdoc>
 | |
|         ///    <para>Construct a new empty schema schemas.</para>
 | |
|         /// </devdoc>
 | |
|         public XmlSchemaSet() : this(new NameTable()) {
 | |
|         }
 | |
|  
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.XmlSchemaSet1"]/*' />
 | |
|         /// <devdoc>
 | |
|         ///    <para>Construct a new empty schema schemas with associated XmlNameTable.
 | |
|         ///       The XmlNameTable is used when loading schemas</para>
 | |
|         /// </devdoc>
 | |
|         public XmlSchemaSet(XmlNameTable nameTable) {
 | |
|             if (nameTable == null) {
 | |
|                 throw new ArgumentNullException("nameTable");
 | |
|             }
 | |
|             this.nameTable = nameTable;
 | |
|             schemas = new SortedList();
 | |
| 
 | |
|             /*schemaLocations = new Dictionary<Uri, XmlSchema>();
 | |
|             chameleonSchemas = new Dictionary<ChameleonKey, XmlSchema>();*/
 | |
|             schemaLocations = new Hashtable();
 | |
|             chameleonSchemas = new Hashtable();
 | |
|             targetNamespaces = new Hashtable();
 | |
|             internalEventHandler = new ValidationEventHandler(InternalValidationCallback);
 | |
|             eventHandler = internalEventHandler;
 | |
|             
 | |
|             readerSettings = new XmlReaderSettings();
 | |
| 
 | |
|             // we don't have to check XmlReaderSettings.EnableLegacyXmlSettings() here because the following
 | |
|             // code will return same result either we are running on v4.5 or later
 | |
|             if (readerSettings.GetXmlResolver() == null)
 | |
|             {
 | |
|                 // The created resolver will be used in the schema validation only
 | |
|                 readerSettings.XmlResolver = new XmlUrlResolver();
 | |
|                 readerSettings.IsXmlResolverSet = false;
 | |
|             }
 | |
|             
 | |
|             readerSettings.NameTable = nameTable;
 | |
|             readerSettings.DtdProcessing = DtdProcessing.Prohibit;
 | |
|     
 | |
|             compilationSettings = new XmlSchemaCompilationSettings();
 | |
|             cachedCompiledInfo = new SchemaInfo();
 | |
|             compileAll = true;
 | |
|         }
 | |
| 
 | |
| 
 | |
| //Public Properties       
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.NameTable"]/*' />
 | |
|         /// <devdoc>
 | |
|         ///    <para>The default XmlNameTable used by the XmlSchemaSet when loading new schemas.</para>
 | |
|         /// </devdoc>
 | |
|         public XmlNameTable NameTable {
 | |
|             get { return nameTable;}
 | |
|         }
 | |
| 
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.ValidationEventHandler"]/*' />
 | |
|         public  event ValidationEventHandler ValidationEventHandler {
 | |
|             add {
 | |
|                 eventHandler -= internalEventHandler;
 | |
|                 eventHandler += value;
 | |
|                 if (eventHandler == null) {
 | |
|                     eventHandler = internalEventHandler;
 | |
|                 }
 | |
|             }
 | |
|             remove {
 | |
|                 eventHandler -= value;
 | |
|                 if (eventHandler == null) {
 | |
|                     eventHandler = internalEventHandler;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.IsCompiled"]/*' />
 | |
|         /// <devdoc>
 | |
|         ///    <para>IsCompiled is true when the schema set is in compiled state</para>
 | |
|         /// </devdoc>
 | |
|         public bool IsCompiled {
 | |
|             get { 
 | |
|                 return isCompiled; 
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.XmlResolver"]/*' />
 | |
|         /// <devdoc>
 | |
|         ///    <para></para>
 | |
|         /// </devdoc>
 | |
|         public XmlResolver XmlResolver {
 | |
|             set {
 | |
|                 readerSettings.XmlResolver = value;
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.CompilationSettings"]/*' />
 | |
|         /// <devdoc>
 | |
|         ///    <para></para>
 | |
|         /// </devdoc>
 | |
|         public XmlSchemaCompilationSettings CompilationSettings {
 | |
|             get {
 | |
|                 return compilationSettings;
 | |
|             }
 | |
|             set {
 | |
|                compilationSettings = value;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Count"]/*' />
 | |
|         /// <devdoc>
 | |
|         ///    <para>Returns the count of schemas in the set</para>
 | |
|         /// </devdoc>
 | |
|         public int Count {
 | |
|             get {
 | |
|                 return schemas.Count;
 | |
|             }
 | |
|         }
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.GlobalElements"]/*' />
 | |
|         /// <devdoc>
 | |
|         ///    <para></para>
 | |
|         /// </devdoc>
 | |
|         public XmlSchemaObjectTable GlobalElements {
 | |
|             get {
 | |
|                 if (elements == null) {
 | |
|                     elements = new XmlSchemaObjectTable();
 | |
|                 }
 | |
|                 return elements;
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.GlobalAttributes"]/*' />
 | |
|         /// <devdoc>
 | |
|         ///    <para></para>
 | |
|         /// </devdoc>
 | |
|         public XmlSchemaObjectTable GlobalAttributes {
 | |
|             get {
 | |
|                 if (attributes == null) {
 | |
|                     attributes = new XmlSchemaObjectTable();
 | |
|                 }
 | |
|                 return attributes;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.GlobalTypes"]/*' />
 | |
|         /// <devdoc>
 | |
|         ///    <para></para>
 | |
|         /// </devdoc>
 | |
|         public XmlSchemaObjectTable GlobalTypes {
 | |
|             get {
 | |
|                 if (schemaTypes == null) {
 | |
|                     schemaTypes = new XmlSchemaObjectTable();
 | |
|                 }
 | |
|                 return schemaTypes;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.SubstitutionGroups"]/*' />
 | |
|         /// <devdoc>
 | |
|         ///    <para></para>
 | |
|         /// </devdoc>
 | |
|         /// 
 | |
|         internal XmlSchemaObjectTable SubstitutionGroups {
 | |
|             get {
 | |
|                 if (substitutionGroups == null) {
 | |
|                     substitutionGroups = new XmlSchemaObjectTable();
 | |
|                 }
 | |
|                 return substitutionGroups;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Table of all types extensions
 | |
|         /// </summary>
 | |
|         internal Hashtable SchemaLocations {
 | |
|             get {
 | |
|                 return schemaLocations;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Table of all types extensions
 | |
|         /// </summary>
 | |
|         internal XmlSchemaObjectTable TypeExtensions {
 | |
|             get {
 | |
|                 if (typeExtensions == null) {
 | |
|                     typeExtensions = new XmlSchemaObjectTable();
 | |
|                 }
 | |
|                 return typeExtensions;
 | |
|             }
 | |
|         }
 | |
| //Public Methods
 | |
| 
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Add1"]/*' />
 | |
|         /// <devdoc>
 | |
|         ///    <para>Add the schema located by the given URL into the schema schemas.
 | |
|         ///       If the given schema references other namespaces, the schemas for those other
 | |
|         ///       namespaces are NOT automatically loaded.</para>
 | |
|         /// </devdoc>
 | |
|         [ResourceConsumption(ResourceScope.Machine)]
 | |
|         [ResourceExposure(ResourceScope.Machine)]
 | |
|         public XmlSchema Add(String targetNamespace, String schemaUri) {
 | |
|             if (schemaUri == null || schemaUri.Length == 0) {
 | |
|                 throw new ArgumentNullException("schemaUri");
 | |
|             }
 | |
|             if (targetNamespace != null) {
 | |
|                 targetNamespace = XmlComplianceUtil.CDataNormalize(targetNamespace);
 | |
|             }
 | |
|             XmlSchema schema = null;
 | |
|             lock (InternalSyncObject) {
 | |
|                 //Check if schema from url has already been added
 | |
|                 XmlResolver tempResolver = readerSettings.GetXmlResolver();
 | |
|                 if ( tempResolver == null ) {
 | |
|                     tempResolver = new XmlUrlResolver();
 | |
|                 }
 | |
|                 Uri tempSchemaUri = tempResolver.ResolveUri(null, schemaUri);
 | |
|                 if (IsSchemaLoaded(tempSchemaUri, targetNamespace, out schema)) {
 | |
|                     return schema;
 | |
|                 }
 | |
|                 else {
 | |
|                     //Url already not processed; Load SOM from url
 | |
|                     XmlReader reader = XmlReader.Create(schemaUri, readerSettings);
 | |
|                     try {
 | |
|                         schema = Add(targetNamespace, ParseSchema(targetNamespace, reader)); //
 | |
|                         while(reader.Read());// wellformness check; 
 | |
|                     }
 | |
|                     finally {
 | |
|                         reader.Close();
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             return schema;
 | |
|         }
 | |
|         
 | |
| 
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Add4"]/*' />
 | |
|         /// <devdoc>
 | |
|         ///    <para>Add the given schema into the schema schemas.
 | |
|         ///       If the given schema references other namespaces, the schemas for those
 | |
|         ///       other namespaces are NOT automatically loaded.</para>
 | |
|         /// </devdoc>
 | |
|         public XmlSchema Add(String targetNamespace, XmlReader schemaDocument) {
 | |
|             if (schemaDocument == null) {
 | |
|                 throw new ArgumentNullException("schemaDocument");
 | |
|             }
 | |
|             if (targetNamespace != null) {
 | |
|                 targetNamespace = XmlComplianceUtil.CDataNormalize(targetNamespace);
 | |
|             }
 | |
|             lock (InternalSyncObject) {
 | |
|                 XmlSchema schema = null;
 | |
|                 Uri schemaUri = new Uri(schemaDocument.BaseURI, UriKind.RelativeOrAbsolute);
 | |
|                 if (IsSchemaLoaded(schemaUri, targetNamespace, out schema)) {
 | |
|                     return schema;
 | |
|                 }
 | |
|                 else {
 | |
|                     DtdProcessing dtdProcessing = this.readerSettings.DtdProcessing;
 | |
|                     SetDtdProcessing(schemaDocument);
 | |
|                     schema = Add(targetNamespace, ParseSchema(targetNamespace, schemaDocument));
 | |
|                     this.readerSettings.DtdProcessing = dtdProcessing; //reset dtdProcessing setting
 | |
|                     return schema;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Add5"]/*' />
 | |
|         /// <devdoc>
 | |
|         ///    <para>Adds all the namespaces defined in the given schemas
 | |
|         ///       (including their associated schemas) to this schemas.</para>
 | |
|         /// </devdoc>
 | |
|         public void Add(XmlSchemaSet schemas) {
 | |
|             if (schemas == null) {
 | |
|                 throw new ArgumentNullException("schemas");
 | |
|             }
 | |
|             if (this == schemas) {
 | |
|                 return;
 | |
|             }
 | |
|             bool thisLockObtained = false;
 | |
|             bool schemasLockObtained = false;
 | |
|             try {
 | |
|                 while(true) {
 | |
|                     Monitor.TryEnter(InternalSyncObject, ref thisLockObtained);
 | |
|                     if (thisLockObtained) {
 | |
|                         Monitor.TryEnter(schemas.InternalSyncObject, ref schemasLockObtained);
 | |
|                         if (schemasLockObtained) {
 | |
|                             break;
 | |
|                         }
 | |
|                         else {
 | |
|                             Monitor.Exit(InternalSyncObject); //Give up this lock and try both again
 | |
|                             thisLockObtained = false;
 | |
|                             Thread.Yield(); //Let the thread that holds the lock run
 | |
|                             continue;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 XmlSchema currentSchema;
 | |
|                 //
 | |
|                 if (schemas.IsCompiled) { 
 | |
|                     CopyFromCompiledSet(schemas);
 | |
|                 }
 | |
|                 else { 
 | |
|                     bool remove = false;
 | |
|                     string tns = null;
 | |
|                     foreach(XmlSchema schema in schemas.SortedSchemas.Values) {
 | |
|                         tns = schema.TargetNamespace;
 | |
|                         if (tns == null) {
 | |
|                             tns = string.Empty;
 | |
|                         }
 | |
|                         if (this.schemas.ContainsKey(schema.SchemaId) || FindSchemaByNSAndUrl(schema.BaseUri, tns, null) != null) { //Do not already existing url
 | |
|                             continue;
 | |
|                         }
 | |
|                         currentSchema = Add(schema.TargetNamespace, schema);
 | |
|                         if(currentSchema == null) {
 | |
|                             remove = true;
 | |
|                             break;
 | |
|                         }
 | |
|                     }
 | |
|                     //Remove all from the set if even one schema in the passed in set is not preprocessed.
 | |
|                     if (remove) {
 | |
|                         foreach(XmlSchema schema in schemas.SortedSchemas.Values) { //Remove all previously added schemas from the set
 | |
|                             this.schemas.Remove(schema.SchemaId); //Might remove schema that was already there and was not added thru this operation
 | |
|                             schemaLocations.Remove(schema.BaseUri);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             finally { //release locks on sets
 | |
|                 if (thisLockObtained) {
 | |
|                     Monitor.Exit(InternalSyncObject);
 | |
|                 }
 | |
|                 if (schemasLockObtained) {
 | |
|                     Monitor.Exit(schemas.InternalSyncObject);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Add6"]/*' />
 | |
|         public XmlSchema Add(XmlSchema schema) {
 | |
|             if (schema == null) {
 | |
|                 throw new ArgumentNullException("schema");
 | |
|             }
 | |
|             lock (InternalSyncObject) {
 | |
|                 if (schemas.ContainsKey(schema.SchemaId)) {
 | |
|                     return schema;
 | |
|                 }
 | |
|                 return Add(schema.TargetNamespace, schema);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Remove"]/*' />
 | |
|         public XmlSchema Remove(XmlSchema schema) {
 | |
|             return Remove(schema, true);
 | |
|         }
 | |
|         
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.RemoveRecursive"]/*' />
 | |
|         public bool RemoveRecursive(XmlSchema schemaToRemove) {
 | |
| 
 | |
|             if (schemaToRemove == null) {
 | |
|                 throw new ArgumentNullException("schemaToRemove");
 | |
|             }
 | |
|             if (!schemas.ContainsKey(schemaToRemove.SchemaId)) {
 | |
|                 return false;
 | |
|             }
 | |
| 
 | |
|             lock (InternalSyncObject) { //Need to lock here so that remove cannot be called while the set is being compiled
 | |
|                 if (schemas.ContainsKey(schemaToRemove.SchemaId)) { //Need to check again
 | |
|                     
 | |
|                     //Build disallowedNamespaces list
 | |
|                     Hashtable disallowedNamespaces = new Hashtable();
 | |
|                     disallowedNamespaces.Add(GetTargetNamespace(schemaToRemove), schemaToRemove);
 | |
|                     string importedNS;
 | |
|                     for (int i = 0; i < schemaToRemove.ImportedNamespaces.Count; i++) {
 | |
|                         importedNS = (string)schemaToRemove.ImportedNamespaces[i];
 | |
|                         if (disallowedNamespaces[importedNS] == null) {
 | |
|                             disallowedNamespaces.Add(importedNS, importedNS);
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     //Removal list is all schemas imported by this schema directly or indirectly
 | |
|                     //Need to check if other schemas in the set import schemaToRemove / any of its imports
 | |
|                     ArrayList needToCheckSchemaList = new ArrayList();
 | |
|                     XmlSchema mainSchema;
 | |
|                     for (int i =0; i < schemas.Count; i++) {
 | |
|                         mainSchema = (XmlSchema)schemas.GetByIndex(i);
 | |
|                         if (mainSchema == schemaToRemove || 
 | |
|                             schemaToRemove.ImportedSchemas.Contains(mainSchema)) {
 | |
|                             continue;
 | |
|                         }
 | |
|                         needToCheckSchemaList.Add(mainSchema);
 | |
|                     }
 | |
| 
 | |
|                     mainSchema = null;
 | |
|                     for (int i = 0; i < needToCheckSchemaList.Count; i++) { //Perf: Not using nested foreach here
 | |
|                         mainSchema = (XmlSchema)needToCheckSchemaList[i];
 | |
|                         
 | |
|                         if (mainSchema.ImportedNamespaces.Count > 0) {
 | |
|                             foreach(string tns in disallowedNamespaces.Keys) {
 | |
|                                 if (mainSchema.ImportedNamespaces.Contains(tns)) {
 | |
|                                     SendValidationEvent(new XmlSchemaException(Res.Sch_SchemaNotRemoved, string.Empty), XmlSeverityType.Warning);
 | |
|                                     return false;
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     Remove(schemaToRemove, true);
 | |
|                     for (int i = 0; i < schemaToRemove.ImportedSchemas.Count; ++i) {
 | |
|                         XmlSchema impSchema = (XmlSchema)schemaToRemove.ImportedSchemas[i];
 | |
|                         Remove(impSchema, true);
 | |
|                     }
 | |
|                     return true;
 | |
|                 }
 | |
|             }
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Contains1"]/*' />
 | |
|         public bool Contains(String targetNamespace) {
 | |
|            if (targetNamespace == null) {
 | |
|                targetNamespace = string.Empty;
 | |
|            }
 | |
|            return targetNamespaces[targetNamespace] != null;
 | |
|         }
 | |
|         
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Contains2"]/*' />
 | |
|         public bool Contains(XmlSchema schema) {
 | |
|             if (schema == null) {
 | |
|                 throw new ArgumentNullException("schema");
 | |
|             }
 | |
|             return schemas.ContainsValue(schema);
 | |
|         }
 | |
| 
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Compile"]/*' />
 | |
|         /// <devdoc>
 | |
|         ///    <para>[To be supplied.]</para>
 | |
|         /// </devdoc>
 | |
|         public void Compile() {
 | |
|             if (isCompiled) {
 | |
|                 return;
 | |
|             }
 | |
|             if (schemas.Count == 0) {
 | |
|                 ClearTables(); //Clear any previously present compiled state left by calling just Remove() on the set
 | |
|                 cachedCompiledInfo = new SchemaInfo();
 | |
|                 isCompiled = true;
 | |
|                 compileAll = false;
 | |
|                 return;
 | |
|             }
 | |
|             lock (InternalSyncObject) {
 | |
|                 
 | |
|                 if (!isCompiled) { //Locking before checking isCompiled to avoid problems with double locking
 | |
|                     Compiler compiler = new Compiler(nameTable, eventHandler, schemaForSchema, compilationSettings);
 | |
|                     SchemaInfo newCompiledInfo = new SchemaInfo();
 | |
|                     int schemaIndex = 0;
 | |
|                     if (!compileAll) { //if we are not compiling everything again, Move the pre-compiled schemas to the compiler's tables
 | |
|                         compiler.ImportAllCompiledSchemas(this); 
 | |
|                     }
 | |
|                     try { //First thing to do in the try block is to acquire locks since finally will try to release them. 
 | |
|                         //If we dont accuire the locks first, and an exception occurs in the code before the locking code, then Threading.SynchronizationLockException will be thrown
 | |
|                         //when attempting to release it in the finally block
 | |
|                         XmlSchema currentSchema;
 | |
|                         XmlSchema xmlNSSchema = Preprocessor.GetBuildInSchema();
 | |
|                         for (schemaIndex = 0; schemaIndex < schemas.Count; schemaIndex++) {
 | |
|                             currentSchema = (XmlSchema)schemas.GetByIndex(schemaIndex);
 | |
|                             
 | |
|                             //Lock schema to be compiled
 | |
| #pragma warning disable 0618 
 | |
|                             //@
 | |
|                             Monitor.Enter(currentSchema);
 | |
| #pragma warning restore 0618
 | |
|                             if (!currentSchema.IsPreprocessed)
 | |
|                             {
 | |
|                                 SendValidationEvent(new XmlSchemaException(Res.Sch_SchemaNotPreprocessed, string.Empty), XmlSeverityType.Error);
 | |
|                                 isCompiled = false;
 | |
|                                 return;
 | |
|                             }
 | |
|                             if (currentSchema.IsCompiledBySet) {
 | |
|                                 if (!compileAll) {
 | |
|                                     continue;
 | |
|                                 }
 | |
|                                 else if ((object)currentSchema == (object)xmlNSSchema) { // prepare for xml namespace schema without cleanup
 | |
|                                     compiler.Prepare(currentSchema, false);
 | |
|                                     continue;
 | |
|                                 }
 | |
|                             }
 | |
|                             compiler.Prepare(currentSchema, true);
 | |
|                         }
 | |
| 
 | |
|                         isCompiled = compiler.Execute(this, newCompiledInfo);
 | |
|                         if (isCompiled) {
 | |
|                             if (!compileAll) {
 | |
|                                 newCompiledInfo.Add(cachedCompiledInfo, eventHandler); //Add all the items from the old to the new compiled object
 | |
|                             }
 | |
|                             compileAll = false;
 | |
|                             cachedCompiledInfo = newCompiledInfo; //Replace the compiled info in the set after successful compilation
 | |
|                         }
 | |
|                     }
 | |
|                     finally {
 | |
|                         //Release locks on all schemas
 | |
|                         XmlSchema currentSchema;
 | |
|                         if (schemaIndex == schemas.Count) {
 | |
|                             schemaIndex--;
 | |
|                         }
 | |
|                         for (int i = schemaIndex; i >= 0; i--) {
 | |
|                             currentSchema = (XmlSchema)schemas.GetByIndex(i);
 | |
|                             if (currentSchema == Preprocessor.GetBuildInSchema()) { //dont re-set compiled flags for xml namespace schema
 | |
|                                 Monitor.Exit(currentSchema);
 | |
|                                 continue;
 | |
|                             }
 | |
|                             currentSchema.IsCompiledBySet = isCompiled;
 | |
|                             Monitor.Exit(currentSchema);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Reprocess"]/*' />
 | |
|         /// <devdoc>
 | |
|         ///    <para>[To be supplied.]</para>
 | |
|         /// </devdoc>
 | |
|         public XmlSchema Reprocess(XmlSchema schema) {
 | |
|             // Due to bug 644477 - this method is tightly coupled (THE CODE IS BASICALLY COPIED) to Remove, Add and AddSchemaToSet
 | |
|             // methods. If you change anything here *make sure* to update Remove/Add/AddSchemaToSet method(s) accordingly.
 | |
|             // The only difference is that we don't touch .schemas collection here to not break a code like this:
 | |
|             // foreach(XmlSchema s in schemaset.schemas) { schemaset.Reprocess(s); }
 | |
|             // This is by purpose.
 | |
|             if (schema == null) {
 | |
|                 throw new ArgumentNullException("schema");
 | |
|             }
 | |
|             if (!schemas.ContainsKey(schema.SchemaId)) {
 | |
|                 throw new ArgumentException(Res.GetString(Res.Sch_SchemaDoesNotExist), "schema");
 | |
|             }
 | |
|             XmlSchema originalSchema = schema;
 | |
|             lock (InternalSyncObject) { //Lock set so that set cannot be compiled in another thread
 | |
| 
 | |
|                 // This code is copied from method:
 | |
|                 // Remove(XmlSchema schema, bool forceCompile) 
 | |
|                 // If you changed anything here go and change the same in Remove(XmlSchema schema, bool forceCompile) method
 | |
|                 #region Copied from Remove(XmlSchema schema, bool forceCompile)
 | |
| 
 | |
|                 RemoveSchemaFromGlobalTables(schema);
 | |
|                 RemoveSchemaFromCaches(schema);
 | |
|                 if (schema.BaseUri != null) {
 | |
|                     schemaLocations.Remove(schema.BaseUri);
 | |
|                 }
 | |
|                 string tns = GetTargetNamespace(schema);
 | |
|                 if (Schemas(tns).Count == 0) { //This is the only schema for that namespace
 | |
|                     targetNamespaces.Remove(tns);
 | |
|                 }
 | |
|                 isCompiled = false;
 | |
|                 compileAll = true; //Force compilation of the whole set; This is when the set is not completely thread-safe
 | |
| 
 | |
|                 #endregion //Copied from Remove(XmlSchema schema, bool forceCompile)
 | |
| 
 | |
| 
 | |
|                 // This code is copied from method:
 | |
|                 // Add(string targetNamespace, XmlSchema schema)
 | |
|                 // If you changed anything here go and change the same in Add(string targetNamespace, XmlSchema schema) method
 | |
|                 #region Copied from Add(string targetNamespace, XmlSchema schema)
 | |
| 
 | |
|                 if (schema.ErrorCount != 0) { //Schema with parsing errors cannot be loaded
 | |
|                     return originalSchema;
 | |
|                 }
 | |
|                 if (PreprocessSchema(ref schema, schema.TargetNamespace)) { //No perf opt for already compiled schemas
 | |
| 
 | |
|                     // This code is copied from method:
 | |
|                     // AddSchemaToSet(XmlSchema schema)
 | |
|                     // If you changed anything here go and change the same in AddSchemaToSet(XmlSchema schema) method
 | |
|                     #region Copied from AddSchemaToSet(XmlSchema schema)
 | |
| 
 | |
|                     //Add to targetNamespaces table
 | |
|                     if (targetNamespaces[tns] == null) {
 | |
|                         targetNamespaces.Add(tns, tns);
 | |
|                     }
 | |
|                     if (schemaForSchema == null && tns == XmlReservedNs.NsXs && schema.SchemaTypes[DatatypeImplementation.QnAnyType] != null) { //it has xs:anyType
 | |
|                         schemaForSchema = schema;
 | |
|                     }
 | |
|                     for (int i = 0; i < schema.ImportedSchemas.Count; ++i) {    //Once preprocessed external schemas property is set
 | |
|                         XmlSchema s = (XmlSchema)schema.ImportedSchemas[i];
 | |
|                         if (!schemas.ContainsKey(s.SchemaId)) {
 | |
|                             schemas.Add(s.SchemaId, s);
 | |
|                         }
 | |
|                         tns = GetTargetNamespace(s);
 | |
|                         if (targetNamespaces[tns] == null) {
 | |
|                             targetNamespaces.Add(tns, tns);
 | |
|                         }
 | |
|                         if (schemaForSchema == null && tns == XmlReservedNs.NsXs && schema.SchemaTypes[DatatypeImplementation.QnAnyType] != null) { //it has xs:anyType
 | |
|                             schemaForSchema = schema;
 | |
|                         }
 | |
|                     }
 | |
|                     #endregion //Copied from AddSchemaToSet(XmlSchema schema)
 | |
|                     return schema;
 | |
|                 }
 | |
|                 #endregion // Copied from Add(string targetNamespace, XmlSchema schema)
 | |
| 
 | |
|                 return originalSchema;
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.CopyTo"]/*' />
 | |
|         /// <devdoc>
 | |
|         ///    <para>[To be supplied.]</para>
 | |
|         /// </devdoc>
 | |
|         public void CopyTo(XmlSchema[] schemas, int index) {
 | |
|             if (schemas == null)
 | |
|                 throw new ArgumentNullException("schemas");
 | |
|             if (index < 0 || index > schemas.Length -1 )
 | |
|                 throw new ArgumentOutOfRangeException("index");
 | |
|             this.schemas.Values.CopyTo(schemas, index);
 | |
|         }
 | |
| 
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Schemas1"]/*' />
 | |
|         /// <devdoc>
 | |
|         ///    <para>[To be supplied.]</para>
 | |
|         /// </devdoc>
 | |
|         public ICollection Schemas() {       
 | |
|             return schemas.Values; 
 | |
|         }
 | |
|         
 | |
|         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Schemas1"]/*' />
 | |
|         /// <devdoc>
 | |
|         ///    <para>[To be supplied.]</para>
 | |
|         /// </devdoc>
 | |
|         public ICollection Schemas(String targetNamespace) {       
 | |
|             ArrayList tnsSchemas = new ArrayList();
 | |
|             XmlSchema currentSchema;
 | |
|             if (targetNamespace == null) {
 | |
|                 targetNamespace = string.Empty;
 | |
|             }
 | |
|             for (int i=0; i < schemas.Count; i++) {
 | |
|                 currentSchema = (XmlSchema)schemas.GetByIndex(i);
 | |
|                 if (GetTargetNamespace(currentSchema) == targetNamespace) {
 | |
|                     tnsSchemas.Add(currentSchema);
 | |
|                 }
 | |
|             }
 | |
|             return tnsSchemas;
 | |
|         }
 | |
|         
 | |
| //Internal Methods
 | |
| 
 | |
|         private XmlSchema Add(string targetNamespace, XmlSchema schema) {
 | |
|             // Due to bug 644477 - this method is tightly coupled (THE CODE IS BASICALLY COPIED) to Reprocess 
 | |
|             // method. If you change anything here *make sure* to update Reprocess method accordingly.
 | |
| 
 | |
|             if (schema == null || schema.ErrorCount != 0) { //Schema with parsing errors cannot be loaded
 | |
|                 return null;    
 | |
|             }
 | |
| 
 | |
|             // This code is copied to method:
 | |
|             // Reprocess(XmlSchema schema) 
 | |
|             // If you changed anything here go and change the same in Reprocess(XmlSchema schema) method
 | |
|             if (PreprocessSchema(ref schema, targetNamespace)) { //No perf opt for already compiled schemas
 | |
|                 AddSchemaToSet(schema);
 | |
|                 isCompiled = false;
 | |
|                 return schema;
 | |
|             }
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
| #if TRUST_COMPILE_STATE
 | |
|         private void AddCompiledSchema(XmlSchema schema) {
 | |
|             if (schema.IsCompiledBySet ) { //trust compiled state always if it is not a chameleon schema
 | |
|                 VerifyTables();
 | |
|                 SchemaInfo newCompiledInfo = new SchemaInfo();
 | |
|                 XmlSchemaObjectTable substitutionGroupsTable = null;
 | |
|                 if (!AddToCompiledInfo(schema, newCompiledInfo, ref substitutionGroupsTable)) { //Error while adding main schema
 | |
|                     return null;
 | |
|                 }
 | |
|                 foreach (XmlSchema impSchema in schema.ImportedSchemas) {
 | |
|                     if (!AddToCompiledInfo(impSchema, newCompiledInfo, ref substitutionGroupsTable)) { //Error while adding imports
 | |
|                         return null;
 | |
|                     }
 | |
|                 }
 | |
|                 newCompiledInfo.Add(cachedCompiledInfo, eventHandler); //Add existing compiled info
 | |
|                 cachedCompiledInfo = newCompiledInfo;
 | |
|                 if (substitutionGroupsTable != null) {
 | |
|                     ProcessNewSubstitutionGroups(substitutionGroupsTable, true);
 | |
|                 }
 | |
|                 if (schemas.Count == 0) { //If its the first compiled schema being added, then set doesnt need to be compiled
 | |
|                     isCompiled = true;
 | |
|                     compileAll = false;
 | |
|                 }
 | |
|                 AddSchemaToSet(schema);
 | |
|                 return schema;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private bool AddToCompiledInfo(XmlSchema schema, SchemaInfo newCompiledInfo, ref XmlSchemaObjectTable substTable) {
 | |
|             //Add schema's compiled tables to the set
 | |
|             if (schema.BaseUri != null && schemaLocations[schema.BaseUri] == null) { //Update schemaLocations table
 | |
|                 schemaLocations.Add(schema.BaseUri, schema);
 | |
|             }
 | |
| 
 | |
|             foreach (XmlSchemaElement element in schema.Elements.Values) {
 | |
|                 if(!AddToTable(elements, element.QualifiedName, element)) {
 | |
|                     RemoveSchemaFromGlobalTables(schema);
 | |
|                     return false;
 | |
|                 }
 | |
|                 XmlQualifiedName head = element.SubstitutionGroup;
 | |
|                 if (!head.IsEmpty) {
 | |
|                     if (substTable == null) {
 | |
|                         substTable = new XmlSchemaObjectTable();
 | |
|                     }
 | |
|                     XmlSchemaSubstitutionGroup substitutionGroup = (XmlSchemaSubstitutionGroup)substTable[head];
 | |
|                     if (substitutionGroup == null) {
 | |
|                         substitutionGroup = new XmlSchemaSubstitutionGroup();
 | |
|                         substitutionGroup.Examplar = head;
 | |
|                         substTable.Add(head, substitutionGroup);
 | |
|                     }
 | |
|                     ArrayList members = substitutionGroup.Members;
 | |
|                     if (!members.Contains(element)) { //Members might contain element if the same schema is included and imported through different paths. Imp, hence will be added to set directly
 | |
|                         members.Add(element);
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             foreach (XmlSchemaAttribute attribute in schema.Attributes.Values) {
 | |
|                 if (!AddToTable(attributes, attribute.QualifiedName, attribute)) {
 | |
|                     RemoveSchemaFromGlobalTables(schema);
 | |
|                     return false;
 | |
|                 }
 | |
|             }
 | |
|             foreach (XmlSchemaType schemaType in schema.SchemaTypes.Values) {
 | |
|                 if (!AddToTable(schemaTypes, schemaType.QualifiedName, schemaType)) {
 | |
|                     RemoveSchemaFromGlobalTables(schema);
 | |
|                     return false;
 | |
|                 }
 | |
|             }
 | |
|             schema.AddCompiledInfo(newCompiledInfo);
 | |
|             
 | |
|             return true;
 | |
|         }
 | |
| #endif
 | |
| 
 | |
|         //For use by the validator when loading schemaLocations in the instance
 | |
|         internal void Add(String targetNamespace, XmlReader reader, Hashtable validatedNamespaces) {
 | |
|             if (reader == null) {
 | |
|                 throw new ArgumentNullException("reader");
 | |
|             }
 | |
|             if (targetNamespace == null) {
 | |
|                 targetNamespace = string.Empty;
 | |
|             }
 | |
|             if (validatedNamespaces[targetNamespace] != null) {
 | |
|                 if (FindSchemaByNSAndUrl(new Uri(reader.BaseURI, UriKind.RelativeOrAbsolute), targetNamespace, null) != null) {
 | |
|                     return;
 | |
|                 }
 | |
|                 else {
 | |
|                     throw new XmlSchemaException(Res.Sch_ComponentAlreadySeenForNS, targetNamespace);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             //Not locking set as this will not be accessible outside the validator
 | |
|             XmlSchema schema;
 | |
|             if (IsSchemaLoaded(new Uri(reader.BaseURI, UriKind.RelativeOrAbsolute), targetNamespace, out schema)) {
 | |
|                 return;
 | |
|             }
 | |
|             else { //top-level schema not present for same url
 | |
|                 schema = ParseSchema(targetNamespace, reader);
 | |
| 
 | |
|                 //Store the previous locations
 | |
|                 DictionaryEntry[] oldLocations = new DictionaryEntry[schemaLocations.Count];
 | |
|                 schemaLocations.CopyTo(oldLocations, 0);
 | |
| 
 | |
|                 //Add to set
 | |
|                 Add(targetNamespace, schema);
 | |
|                 if (schema.ImportedSchemas.Count > 0) { //Check imports
 | |
|                     string tns;
 | |
|                     for (int i = 0; i < schema.ImportedSchemas.Count; ++i) {
 | |
|                         XmlSchema impSchema = (XmlSchema)schema.ImportedSchemas[i];
 | |
|                         tns = impSchema.TargetNamespace;
 | |
|                         if (tns == null) {
 | |
|                             tns = string.Empty;
 | |
|                         }
 | |
|                         if (validatedNamespaces[tns] != null && (FindSchemaByNSAndUrl(impSchema.BaseUri, tns, oldLocations) == null) ) {
 | |
|                             RemoveRecursive(schema);
 | |
|                             throw new XmlSchemaException(Res.Sch_ComponentAlreadySeenForNS, tns);
 | |
|                         }
 | |
|                     }
 | |
|                  }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         internal XmlSchema FindSchemaByNSAndUrl(Uri schemaUri, string ns, DictionaryEntry[] locationsTable) {
 | |
|             if (schemaUri == null || schemaUri.OriginalString.Length == 0) {
 | |
|                 return null;
 | |
|             }
 | |
|             XmlSchema schema = null;
 | |
|             if (locationsTable == null) {
 | |
|                 schema = (XmlSchema)schemaLocations[schemaUri];
 | |
|             }
 | |
|             else {
 | |
|                 for (int i = 0; i < locationsTable.Length; i++) {
 | |
|                     if (schemaUri.Equals(locationsTable[i].Key)) {
 | |
|                         schema = (XmlSchema)locationsTable[i].Value;
 | |
|                         break;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             if (schema != null) {
 | |
|                 Debug.Assert(ns != null);
 | |
|                 string tns = schema.TargetNamespace == null ? string.Empty : schema.TargetNamespace;
 | |
|                 if (tns == ns) {
 | |
|                     return schema;
 | |
|                 }
 | |
|                 else if (tns == string.Empty) { //There could be a chameleon for same ns
 | |
|                     // It is OK to pass in the schema we have found so far, since it must have the schemaUri we're looking for
 | |
|                     // (we found it that way above) and it must be the original chameleon schema (the one without target ns)
 | |
|                     // as we don't add the chameleon copies into the locations tables above.
 | |
|                     Debug.Assert(schema.BaseUri.Equals(schemaUri));
 | |
|                     ChameleonKey cKey = new ChameleonKey(ns, schema);
 | |
|                     schema = (XmlSchema)chameleonSchemas[cKey]; //Need not clone if a schema for that namespace already exists
 | |
|                 }
 | |
|                 else {
 | |
|                     schema = null;
 | |
|                 }
 | |
|             }
 | |
|             return schema;
 | |
|         }
 | |
| 
 | |
|         private void SetDtdProcessing(XmlReader reader) {
 | |
|             if (reader.Settings != null) {
 | |
|                 this.readerSettings.DtdProcessing = reader.Settings.DtdProcessing;
 | |
|             }  
 | |
|             else {
 | |
|                 XmlTextReader v1Reader = reader as XmlTextReader;
 | |
|                 if (v1Reader != null) {
 | |
|                    this.readerSettings.DtdProcessing = v1Reader.DtdProcessing;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private void AddSchemaToSet(XmlSchema schema) {
 | |
|             // Due to bug 644477 - this method is tightly coupled (THE CODE IS BASICALLY COPIED) to Reprocess 
 | |
|             // method. If you change anything here *make sure* to update Reprocess method accordingly.
 | |
| 
 | |
|             schemas.Add(schema.SchemaId, schema);
 | |
|             //Add to targetNamespaces table
 | |
| 
 | |
|             // This code is copied to method:
 | |
|             // Reprocess(XmlSchema schema) 
 | |
|             // If you changed anything here go and change the same in Reprocess(XmlSchema schema) method
 | |
|             #region This code is copied to Reprocess(XmlSchema schema) method
 | |
| 
 | |
|             string tns = GetTargetNamespace(schema);
 | |
|             if (targetNamespaces[tns] == null) {
 | |
|                 targetNamespaces.Add(tns, tns);
 | |
|             }
 | |
|             if (schemaForSchema == null && tns == XmlReservedNs.NsXs && schema.SchemaTypes[DatatypeImplementation.QnAnyType] != null) { //it has xs:anyType
 | |
|                 schemaForSchema = schema;
 | |
|             }
 | |
|             for (int i = 0; i < schema.ImportedSchemas.Count; ++i) {    //Once preprocessed external schemas property is set
 | |
|                 XmlSchema s = (XmlSchema)schema.ImportedSchemas[i]; 
 | |
|                 if (!schemas.ContainsKey(s.SchemaId)) {
 | |
|                     schemas.Add(s.SchemaId, s);
 | |
|                 }
 | |
|                 tns = GetTargetNamespace(s);
 | |
|                 if (targetNamespaces[tns] == null) {
 | |
|                     targetNamespaces.Add(tns, tns);
 | |
|                 }
 | |
|                 if (schemaForSchema == null && tns == XmlReservedNs.NsXs && schema.SchemaTypes[DatatypeImplementation.QnAnyType] != null) { //it has xs:anyType
 | |
|                     schemaForSchema = schema;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             #endregion // This code is copied to Reprocess(XmlSchema schema) method
 | |
|         }
 | |
| 
 | |
|         private void ProcessNewSubstitutionGroups(XmlSchemaObjectTable substitutionGroupsTable, bool resolve) {
 | |
|             foreach(XmlSchemaSubstitutionGroup substGroup in substitutionGroupsTable.Values) {
 | |
|                 if (resolve) { //Resolve substitutionGroups within this schema
 | |
|                     ResolveSubstitutionGroup(substGroup, substitutionGroupsTable);
 | |
|                 }
 | |
| 
 | |
|                 //Add or Merge new substitutionGroups with those that already exist in the set 
 | |
|                 XmlQualifiedName head = substGroup.Examplar;
 | |
|                 XmlSchemaSubstitutionGroup oldSubstGroup = (XmlSchemaSubstitutionGroup)substitutionGroups[head];
 | |
|                 if (oldSubstGroup != null) {
 | |
|                     for (int i = 0; i < substGroup.Members.Count; ++i) {
 | |
|                         if (!oldSubstGroup.Members.Contains(substGroup.Members[i])) {
 | |
|                             oldSubstGroup.Members.Add(substGroup.Members[i]);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 else {
 | |
|                     AddToTable(substitutionGroups, head, substGroup);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|    
 | |
|         private void ResolveSubstitutionGroup(XmlSchemaSubstitutionGroup substitutionGroup, XmlSchemaObjectTable substTable) {
 | |
|             List<XmlSchemaElement> newMembers = null;
 | |
|             XmlSchemaElement headElement = (XmlSchemaElement)elements[substitutionGroup.Examplar];
 | |
|             if (substitutionGroup.Members.Contains(headElement)) {// already checked
 | |
|                 return;
 | |
|             }
 | |
|             for (int i = 0; i < substitutionGroup.Members.Count; ++i) {
 | |
|                 XmlSchemaElement element = (XmlSchemaElement)substitutionGroup.Members[i];
 | |
| 
 | |
|                 //Chain to other head's that are members of this head's substGroup
 | |
|                 XmlSchemaSubstitutionGroup g = (XmlSchemaSubstitutionGroup)substTable[element.QualifiedName];
 | |
|                 if (g != null) {
 | |
|                     ResolveSubstitutionGroup(g, substTable);
 | |
|                     for (int j = 0; j < g.Members.Count; ++j) {
 | |
|                         XmlSchemaElement element1 = (XmlSchemaElement)g.Members[j];
 | |
|                         if (element1 != element) { //Exclude the head
 | |
|                             if (newMembers == null) {
 | |
|                                 newMembers = new List<XmlSchemaElement>();
 | |
|                             }
 | |
|                             newMembers.Add(element1);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             if (newMembers != null) {
 | |
|                 for (int i = 0; i < newMembers.Count; ++i) {
 | |
|                     substitutionGroup.Members.Add(newMembers[i]);
 | |
|                 }
 | |
|             }
 | |
|             substitutionGroup.Members.Add(headElement);
 | |
|         }
 | |
| 
 | |
|         internal XmlSchema Remove(XmlSchema schema, bool forceCompile) {
 | |
|             // Due to bug 644477 - this method is tightly coupled (THE CODE IS BASICALLY COPIED) to Reprocess 
 | |
|             // method. If you change anything here *make sure* to update Reprocess method accordingly.
 | |
|             if (schema == null) {
 | |
|                 throw new ArgumentNullException("schema");
 | |
|             }
 | |
|             lock (InternalSyncObject) { //Need to lock here so that remove cannot be called while the set is being compiled
 | |
|                 if (schemas.ContainsKey(schema.SchemaId)) {
 | |
| 
 | |
|                     // This code is copied to method:
 | |
|                     // Reprocess(XmlSchema schema) 
 | |
|                     // If you changed anything here go and change the same in Reprocess(XmlSchema schema) method
 | |
|                     #region This code is copied to Reprocess(XmlSchema schema) method
 | |
| 
 | |
|                     if (forceCompile) {
 | |
|                         RemoveSchemaFromGlobalTables(schema);
 | |
|                         RemoveSchemaFromCaches(schema);
 | |
|                     }
 | |
|                     schemas.Remove(schema.SchemaId);
 | |
|                     if (schema.BaseUri != null) {
 | |
|                         schemaLocations.Remove(schema.BaseUri);
 | |
|                     }
 | |
|                     string tns = GetTargetNamespace(schema);
 | |
|                     if (Schemas(tns).Count == 0) { //This is the only schema for that namespace
 | |
|                         targetNamespaces.Remove(tns);
 | |
|                     }
 | |
|                     if (forceCompile) {
 | |
|                         isCompiled = false;
 | |
|                         compileAll = true; //Force compilation of the whole set; This is when the set is not completely thread-safe
 | |
|                     }
 | |
|                     return schema;
 | |
| 
 | |
|                     #endregion // This code is copied to Reprocess(XmlSchema schema) method
 | |
|                 }
 | |
|             }
 | |
|             return null;
 | |
|         }
 | |
| 
 | |
|         private void ClearTables() {
 | |
|             GlobalElements.Clear();
 | |
|             GlobalAttributes.Clear();
 | |
|             GlobalTypes.Clear();
 | |
|             SubstitutionGroups.Clear();
 | |
|             TypeExtensions.Clear();
 | |
|         }
 | |
| 
 | |
|         internal bool PreprocessSchema(ref XmlSchema schema, string targetNamespace) {
 | |
|             Preprocessor prep = new Preprocessor(nameTable, GetSchemaNames(nameTable), eventHandler, compilationSettings);
 | |
|             prep.XmlResolver = readerSettings.GetXmlResolver_CheckConfig();
 | |
|             prep.ReaderSettings = readerSettings;
 | |
|             prep.SchemaLocations = schemaLocations;
 | |
|             prep.ChameleonSchemas = chameleonSchemas;
 | |
|             bool hasErrors = prep.Execute(schema, targetNamespace, true);
 | |
|             schema = prep.RootSchema; //For any root level chameleon cloned
 | |
|             return hasErrors;
 | |
|         }
 | |
|         
 | |
|         internal XmlSchema ParseSchema(string targetNamespace, XmlReader reader) {
 | |
|             XmlNameTable readerNameTable = reader.NameTable;
 | |
|             SchemaNames schemaNames = GetSchemaNames(readerNameTable);
 | |
|             Parser parser = new Parser(SchemaType.XSD, readerNameTable, schemaNames, eventHandler);
 | |
|             parser.XmlResolver = readerSettings.GetXmlResolver_CheckConfig();
 | |
|             SchemaType schemaType;
 | |
|             try {
 | |
|                 schemaType = parser.Parse(reader, targetNamespace);
 | |
|             }
 | |
|             catch(XmlSchemaException e) {
 | |
|                 SendValidationEvent(e, XmlSeverityType.Error);
 | |
|                 return null;
 | |
|             }
 | |
|             return parser.XmlSchema;
 | |
|         }
 | |
|         
 | |
|         internal void CopyFromCompiledSet(XmlSchemaSet otherSet) {
 | |
|             XmlSchema currentSchema;
 | |
|             SortedList copyFromList = otherSet.SortedSchemas;
 | |
|             bool setIsCompiled = schemas.Count == 0 ? true : false; 
 | |
|             ArrayList existingSchemas = new ArrayList();
 | |
| 
 | |
|             SchemaInfo newCompiledInfo = new SchemaInfo();
 | |
|             Uri baseUri;
 | |
|             for(int i=0; i < copyFromList.Count; i++) {
 | |
|                 currentSchema = (XmlSchema)copyFromList.GetByIndex(i);
 | |
|                 baseUri = currentSchema.BaseUri;
 | |
|                 if (schemas.ContainsKey(currentSchema.SchemaId) || (baseUri != null && baseUri.OriginalString.Length != 0 && schemaLocations[baseUri] != null)) {
 | |
|                     existingSchemas.Add(currentSchema);
 | |
|                     continue;
 | |
|                 }
 | |
|                 schemas.Add(currentSchema.SchemaId, currentSchema);
 | |
|                 if (baseUri != null && baseUri.OriginalString.Length != 0) {
 | |
|                     schemaLocations.Add(baseUri, currentSchema);
 | |
|                 }
 | |
|                 string tns = GetTargetNamespace(currentSchema);
 | |
|                 if (targetNamespaces[tns] == null) {
 | |
|                     targetNamespaces.Add(tns, tns);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             VerifyTables();
 | |
|             foreach (XmlSchemaElement element in otherSet.GlobalElements.Values) {
 | |
|                 if(!AddToTable(elements, element.QualifiedName, element)) {
 | |
|                     goto RemoveAll;
 | |
|                 }
 | |
|             }
 | |
|             foreach (XmlSchemaAttribute attribute in otherSet.GlobalAttributes.Values) {
 | |
|                 if (!AddToTable(attributes, attribute.QualifiedName, attribute)) {
 | |
|                     goto RemoveAll;
 | |
|                 }
 | |
|             }
 | |
|             foreach (XmlSchemaType schemaType in otherSet.GlobalTypes.Values) {
 | |
|                 if (!AddToTable(schemaTypes, schemaType.QualifiedName, schemaType)) {
 | |
|                     goto RemoveAll;
 | |
|                 }
 | |
|             }
 | |
|             //
 | |
|             ProcessNewSubstitutionGroups(otherSet.SubstitutionGroups, false);
 | |
| 
 | |
|             newCompiledInfo.Add(cachedCompiledInfo, eventHandler); //Add all the items from the old to the new compiled object
 | |
|             newCompiledInfo.Add(otherSet.CompiledInfo,eventHandler); //
 | |
|             cachedCompiledInfo = newCompiledInfo; //Replace the compiled info in the set after successful compilation
 | |
|             if (setIsCompiled) {
 | |
|                 isCompiled = true;
 | |
|                 compileAll = false;
 | |
|             }
 | |
|             return;
 | |
|         
 | |
|             RemoveAll:
 | |
|                 foreach (XmlSchema schemaToRemove in copyFromList.Values) {
 | |
|                     if (!existingSchemas.Contains(schemaToRemove)) {
 | |
|                         Remove(schemaToRemove, false);
 | |
|                     }
 | |
|                 }
 | |
|                 foreach (XmlSchemaElement elementToRemove in otherSet.GlobalElements.Values) {
 | |
|                     if(!existingSchemas.Contains((XmlSchema)elementToRemove.Parent)) {
 | |
|                         elements.Remove(elementToRemove.QualifiedName);
 | |
|                     }
 | |
|                 }
 | |
|                 foreach (XmlSchemaAttribute attributeToRemove in otherSet.GlobalAttributes.Values) {
 | |
|                     if(!existingSchemas.Contains((XmlSchema)attributeToRemove.Parent)) {
 | |
|                         attributes.Remove(attributeToRemove.QualifiedName);
 | |
|                     }
 | |
|                 }
 | |
|                 foreach (XmlSchemaType schemaTypeToRemove in otherSet.GlobalTypes.Values) {
 | |
|                     if(!existingSchemas.Contains((XmlSchema)schemaTypeToRemove.Parent)) {
 | |
|                         schemaTypes.Remove(schemaTypeToRemove.QualifiedName);
 | |
|                     }
 | |
|                 }
 | |
|         }
 | |
| 
 | |
|         internal SchemaInfo CompiledInfo {
 | |
|             get {
 | |
|                 return cachedCompiledInfo; 
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         internal XmlReaderSettings ReaderSettings {
 | |
|             get {
 | |
|                 return readerSettings;
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         internal XmlResolver GetResolver() {
 | |
|             return readerSettings.GetXmlResolver_CheckConfig();
 | |
|         }
 | |
|         
 | |
|         internal ValidationEventHandler GetEventHandler() {
 | |
|             return eventHandler;
 | |
|         }
 | |
| 
 | |
|         internal SchemaNames GetSchemaNames(XmlNameTable nt) {
 | |
|             if (nameTable != nt) {
 | |
|                 return new SchemaNames(nt);
 | |
|             }
 | |
|             else {
 | |
|                 if (schemaNames == null) {
 | |
|                     schemaNames = new SchemaNames( nameTable );
 | |
|                 }
 | |
|                 return schemaNames;
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         internal bool IsSchemaLoaded(Uri schemaUri, string targetNamespace, out XmlSchema schema) {
 | |
|             schema = null;
 | |
|             if (targetNamespace == null) {
 | |
|                 targetNamespace = string.Empty;
 | |
|             }
 | |
|             if (GetSchemaByUri(schemaUri, out schema)) {
 | |
|                 if (schemas.ContainsKey(schema.SchemaId) && (targetNamespace.Length == 0 || targetNamespace == schema.TargetNamespace)) { //schema is present in set
 | |
|                     //Schema found
 | |
|                 }
 | |
|                 else if (schema.TargetNamespace == null) { //If schema not in set or namespace doesnt match, then it might be a chameleon
 | |
|                     XmlSchema chameleonSchema = FindSchemaByNSAndUrl(schemaUri, targetNamespace, null);
 | |
|                     if (chameleonSchema != null && schemas.ContainsKey(chameleonSchema.SchemaId)) {
 | |
|                         schema = chameleonSchema;
 | |
|                     }
 | |
|                     else {
 | |
|                         schema = Add(targetNamespace, schema);
 | |
|                     }
 | |
|                 }
 | |
|                 else if (targetNamespace.Length != 0 && targetNamespace != schema.TargetNamespace) {
 | |
|                     SendValidationEvent(new XmlSchemaException(Res.Sch_MismatchTargetNamespaceEx, new string[] { targetNamespace, schema.TargetNamespace }), XmlSeverityType.Error);
 | |
|                     schema = null;
 | |
|                 }
 | |
|                 else {
 | |
|                     //If here, schema not present in set but in loc and might be added in loc through an earlier include
 | |
|                     //S.TNS != null && ( tns == null or tns == s.TNS)
 | |
|                     AddSchemaToSet(schema);
 | |
|                 }
 | |
|                 return true; //Schema Found
 | |
|            }
 | |
|            return false;
 | |
|         }
 | |
| 
 | |
|         internal bool GetSchemaByUri(Uri schemaUri, out XmlSchema schema) {
 | |
|             schema = null;
 | |
|             if (schemaUri == null || schemaUri.OriginalString.Length == 0) {
 | |
|                 return false;                    
 | |
|             }                    
 | |
|             schema = (XmlSchema)schemaLocations[schemaUri];
 | |
|             if (schema != null) {
 | |
|                 return true;
 | |
|             }
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         internal string GetTargetNamespace(XmlSchema schema) {
 | |
|             return schema.TargetNamespace == null ? string.Empty : schema.TargetNamespace;
 | |
|         }
 | |
| 
 | |
| 
 | |
|         internal SortedList SortedSchemas {
 | |
|             get {
 | |
|                 return schemas;
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         internal bool CompileAll {
 | |
|             get {
 | |
|                 return compileAll;
 | |
|             }
 | |
|         }
 | |
| 
 | |
| //Private Methods
 | |
|         private void RemoveSchemaFromCaches(XmlSchema schema) {
 | |
|             //Remove From ChameleonSchemas and schemaLocations cache
 | |
|             List<XmlSchema> reprocessList = new List<XmlSchema>();
 | |
|             schema.GetExternalSchemasList(reprocessList, schema);
 | |
|             for (int i = 0; i < reprocessList.Count; ++i) { //Remove schema from schemaLocations & chameleonSchemas tables
 | |
|                 if (reprocessList[i].BaseUri != null && reprocessList[i].BaseUri.OriginalString.Length != 0) {
 | |
|                     schemaLocations.Remove(reprocessList[i].BaseUri);
 | |
|                 }
 | |
|                 //Remove from chameleon table
 | |
|                 ICollection chameleonKeys = chameleonSchemas.Keys;
 | |
|                 ArrayList removalList = new ArrayList();
 | |
|                 foreach(ChameleonKey cKey in chameleonKeys) {
 | |
|                     if (cKey.chameleonLocation.Equals(reprocessList[i].BaseUri)) {
 | |
|                         // The key will have the originalSchema set to null if the location was not empty
 | |
|                         //   otherwise we need to care about it as there may be more chameleon schemas without
 | |
|                         //   a base URI and we want to remove only those which were created as a clone of the one
 | |
|                         //   we're removing.
 | |
|                         if (cKey.originalSchema == null || Ref.ReferenceEquals(cKey.originalSchema, reprocessList[i])) {
 | |
|                             removalList.Add(cKey);
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 for (int j = 0; j < removalList.Count; ++j) {
 | |
|                     chameleonSchemas.Remove(removalList[j]);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private void RemoveSchemaFromGlobalTables(XmlSchema schema) {
 | |
|             if (schemas.Count == 0) {
 | |
|                 return;                    
 | |
|             }
 | |
|             VerifyTables();                
 | |
|             foreach (XmlSchemaElement elementToRemove in schema.Elements.Values) {
 | |
|                 XmlSchemaElement elem = (XmlSchemaElement)elements[elementToRemove.QualifiedName];
 | |
|                 if (elem == elementToRemove) {
 | |
|                     elements.Remove(elementToRemove.QualifiedName);
 | |
|                 }
 | |
|             }
 | |
|             foreach (XmlSchemaAttribute attributeToRemove in schema.Attributes.Values) {
 | |
|                 XmlSchemaAttribute attr = (XmlSchemaAttribute)attributes[attributeToRemove.QualifiedName];
 | |
|                 if (attr == attributeToRemove) {
 | |
|                     attributes.Remove(attributeToRemove.QualifiedName);
 | |
|                 }
 | |
|             }
 | |
|             foreach (XmlSchemaType schemaTypeToRemove in schema.SchemaTypes.Values) {
 | |
|                 XmlSchemaType schemaType = (XmlSchemaType)schemaTypes[schemaTypeToRemove.QualifiedName];
 | |
|                 if (schemaType == schemaTypeToRemove) {
 | |
|                     schemaTypes.Remove(schemaTypeToRemove.QualifiedName);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         private bool AddToTable(XmlSchemaObjectTable table, XmlQualifiedName qname, XmlSchemaObject item) {
 | |
|             if (qname.Name.Length == 0) {
 | |
|                 return true;
 | |
|             }
 | |
|             XmlSchemaObject existingObject = (XmlSchemaObject)table[qname]; 
 | |
|             if (existingObject != null) {
 | |
|                 if (existingObject == item || existingObject.SourceUri == item.SourceUri) {
 | |
|                     return true;
 | |
|                 }
 | |
|                 string code = string.Empty;
 | |
|                 if (item is XmlSchemaComplexType) {
 | |
|                     code = Res.Sch_DupComplexType;
 | |
|                 } 
 | |
|                 else if (item is XmlSchemaSimpleType) {
 | |
|                     code = Res.Sch_DupSimpleType;
 | |
|                 } 
 | |
|                 else if (item is XmlSchemaElement) {
 | |
|                     code = Res.Sch_DupGlobalElement;
 | |
|                 } 
 | |
|                 else if (item is XmlSchemaAttribute) {
 | |
|                     if (qname.Namespace == XmlReservedNs.NsXml) {
 | |
|                         XmlSchema schemaForXmlNS = Preprocessor.GetBuildInSchema();
 | |
|                         XmlSchemaObject builtInAttribute = schemaForXmlNS.Attributes[qname];
 | |
|                         if (existingObject == builtInAttribute) { //replace built-in one
 | |
|                             table.Insert(qname, item);
 | |
|                             return true;
 | |
|                         }
 | |
|                         else if (item == builtInAttribute) { //trying to overwrite customer's component with built-in, ignore built-in
 | |
|                             return true;
 | |
|                         }
 | |
|                     }
 | |
|                     code = Res.Sch_DupGlobalAttribute;
 | |
|                 } 
 | |
|                 SendValidationEvent(new XmlSchemaException(code,qname.ToString()), XmlSeverityType.Error);
 | |
|                 return false;
 | |
|             } 
 | |
|             else {
 | |
|                 table.Add(qname, item);
 | |
|                 return true;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private void VerifyTables() {
 | |
|             if (elements == null) {
 | |
|                 elements = new XmlSchemaObjectTable();
 | |
|             }
 | |
|             if (attributes == null) {
 | |
|                 attributes = new XmlSchemaObjectTable();
 | |
|             }
 | |
|             if (schemaTypes == null) {
 | |
|                 schemaTypes = new XmlSchemaObjectTable();
 | |
|             }
 | |
|             if (substitutionGroups == null) {
 | |
|                 substitutionGroups = new XmlSchemaObjectTable();
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         private void InternalValidationCallback(object sender, ValidationEventArgs e ) {
 | |
|             if (e.Severity == XmlSeverityType.Error) {
 | |
|                 throw e.Exception;
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         private void SendValidationEvent(XmlSchemaException e, XmlSeverityType severity) {
 | |
|             if (eventHandler != null) {
 | |
|                 eventHandler(this, new ValidationEventArgs(e, severity));
 | |
|             } 
 | |
|             else {
 | |
|                 throw e;
 | |
|             }
 | |
|         }
 | |
|     };
 | |
| #endif
 | |
| }
 |