1 //------------------------------------------------------------------------------
2 // <copyright file="XmlSchemaSet.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
7 using System.Diagnostics;
8 using System.Collections;
9 using System.Threading;
10 using System.Collections.Generic;
11 using System.Runtime.Versioning;
12 
13 namespace System.Xml.Schema {
14 #if SILVERLIGHT
15     public class XmlSchemaSet
16     {
17         //Empty XmlSchemaSet class to enable backward compatibility of XmlSchemaProvideAttribute
18         //Add private ctor to prevent constructing of this class
XmlSchemaSet()19         XmlSchemaSet() { }
20     }
21 #else
22     /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet"]/*' />
23     /// <devdoc>
24     ///    <para>The XmlSchemaSet contains a set of namespace URI's.
25     ///       Each namespace also have an associated private data cache
26     ///       corresponding to the XML-Data Schema or W3C XML Schema.
27     ///       The XmlSchemaSet will able to load only XSD schemas,
28     ///       and compile them into an internal "cooked schema representation".
29     ///       The Validate method then uses this internal representation for
30     ///       efficient runtime validation of any given subtree.</para>
31     /// </devdoc>
32     public class XmlSchemaSet {
33         XmlNameTable nameTable;
34         SchemaNames schemaNames;
35         SortedList schemas;              // List of source schemas
36 
37         //Event handling
38         ValidationEventHandler internalEventHandler;
39         ValidationEventHandler eventHandler;
40 
41         bool isCompiled = false;
42 
43         //Dictionary<Uri, XmlSchema> schemaLocations;
44         //Dictionary<ChameleonKey, XmlSchema> chameleonSchemas;
45         Hashtable schemaLocations;
46         Hashtable chameleonSchemas;
47 
48         Hashtable targetNamespaces;
49         bool compileAll;
50 
51         //Cached Compiled Info
52         SchemaInfo cachedCompiledInfo;
53 
54         //Reader settings to parse schema
55         XmlReaderSettings readerSettings;
56         XmlSchema schemaForSchema;  //Only one schema for schema per set
57 
58         //Schema compilation settings
59         XmlSchemaCompilationSettings compilationSettings;
60 
61         internal XmlSchemaObjectTable elements;
62         internal XmlSchemaObjectTable attributes;
63         internal XmlSchemaObjectTable schemaTypes;
64         internal XmlSchemaObjectTable substitutionGroups;
65         private XmlSchemaObjectTable typeExtensions;
66 
67         //Thread safety
68         private Object internalSyncObject;
69         internal Object InternalSyncObject {
70             get {
71                 if (internalSyncObject == null) {
72                     Object o = new Object();
73                     Interlocked.CompareExchange<Object>(ref internalSyncObject, o, null);
74                 }
75                 return internalSyncObject;
76             }
77         }
78 
79 //Constructors
80 
81         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.XmlSchemaSet"]/*' />
82         /// <devdoc>
83         ///    <para>Construct a new empty schema schemas.</para>
84         /// </devdoc>
85         public XmlSchemaSet() : this(new NameTable()) {
86         }
87 
88         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.XmlSchemaSet1"]/*' />
89         /// <devdoc>
90         ///    <para>Construct a new empty schema schemas with associated XmlNameTable.
91         ///       The XmlNameTable is used when loading schemas</para>
92         /// </devdoc>
93         public XmlSchemaSet(XmlNameTable nameTable) {
94             if (nameTable == null) {
95                 throw new ArgumentNullException("nameTable");
96             }
97             this.nameTable = nameTable;
98             schemas = new SortedList();
99 
100             /*schemaLocations = new Dictionary<Uri, XmlSchema>();
101             chameleonSchemas = new Dictionary<ChameleonKey, XmlSchema>();*/
102             schemaLocations = new Hashtable();
103             chameleonSchemas = new Hashtable();
104             targetNamespaces = new Hashtable();
105             internalEventHandler = new ValidationEventHandler(InternalValidationCallback);
106             eventHandler = internalEventHandler;
107 
108             readerSettings = new XmlReaderSettings();
109 
110             // we don't have to check XmlReaderSettings.EnableLegacyXmlSettings() here because the following
111             // code will return same result either we are running on v4.5 or later
112             if (readerSettings.GetXmlResolver() == null)
113             {
114                 // The created resolver will be used in the schema validation only
115                 readerSettings.XmlResolver = new XmlUrlResolver();
116                 readerSettings.IsXmlResolverSet = false;
117             }
118 
119             readerSettings.NameTable = nameTable;
120             readerSettings.DtdProcessing = DtdProcessing.Prohibit;
121 
122             compilationSettings = new XmlSchemaCompilationSettings();
123             cachedCompiledInfo = new SchemaInfo();
124             compileAll = true;
125         }
126 
127 
128 //Public Properties
129         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.NameTable"]/*' />
130         /// <devdoc>
131         ///    <para>The default XmlNameTable used by the XmlSchemaSet when loading new schemas.</para>
132         /// </devdoc>
133         public XmlNameTable NameTable {
134             get { return nameTable;}
135         }
136 
137         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.ValidationEventHandler"]/*' />
138         public  event ValidationEventHandler ValidationEventHandler {
139             add {
140                 eventHandler -= internalEventHandler;
141                 eventHandler += value;
142                 if (eventHandler == null) {
143                     eventHandler = internalEventHandler;
144                 }
145             }
146             remove {
147                 eventHandler -= value;
148                 if (eventHandler == null) {
149                     eventHandler = internalEventHandler;
150                 }
151             }
152         }
153 
154         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.IsCompiled"]/*' />
155         /// <devdoc>
156         ///    <para>IsCompiled is true when the schema set is in compiled state</para>
157         /// </devdoc>
158         public bool IsCompiled {
159             get {
160                 return isCompiled;
161             }
162         }
163 
164         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.XmlResolver"]/*' />
165         /// <devdoc>
166         ///    <para></para>
167         /// </devdoc>
168         public XmlResolver XmlResolver {
169             set {
170                 readerSettings.XmlResolver = value;
171             }
172         }
173 
174         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.CompilationSettings"]/*' />
175         /// <devdoc>
176         ///    <para></para>
177         /// </devdoc>
178         public XmlSchemaCompilationSettings CompilationSettings {
179             get {
180                 return compilationSettings;
181             }
182             set {
183                compilationSettings = value;
184             }
185         }
186 
187         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Count"]/*' />
188         /// <devdoc>
189         ///    <para>Returns the count of schemas in the set</para>
190         /// </devdoc>
191         public int Count {
192             get {
193                 return schemas.Count;
194             }
195         }
196         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.GlobalElements"]/*' />
197         /// <devdoc>
198         ///    <para></para>
199         /// </devdoc>
200         public XmlSchemaObjectTable GlobalElements {
201             get {
202                 if (elements == null) {
203                     elements = new XmlSchemaObjectTable();
204                 }
205                 return elements;
206             }
207         }
208 
209         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.GlobalAttributes"]/*' />
210         /// <devdoc>
211         ///    <para></para>
212         /// </devdoc>
213         public XmlSchemaObjectTable GlobalAttributes {
214             get {
215                 if (attributes == null) {
216                     attributes = new XmlSchemaObjectTable();
217                 }
218                 return attributes;
219             }
220         }
221 
222         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.GlobalTypes"]/*' />
223         /// <devdoc>
224         ///    <para></para>
225         /// </devdoc>
226         public XmlSchemaObjectTable GlobalTypes {
227             get {
228                 if (schemaTypes == null) {
229                     schemaTypes = new XmlSchemaObjectTable();
230                 }
231                 return schemaTypes;
232             }
233         }
234 
235         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.SubstitutionGroups"]/*' />
236         /// <devdoc>
237         ///    <para></para>
238         /// </devdoc>
239         ///
240         internal XmlSchemaObjectTable SubstitutionGroups {
241             get {
242                 if (substitutionGroups == null) {
243                     substitutionGroups = new XmlSchemaObjectTable();
244                 }
245                 return substitutionGroups;
246             }
247         }
248 
249         /// <summary>
250         /// Table of all types extensions
251         /// </summary>
252         internal Hashtable SchemaLocations {
253             get {
254                 return schemaLocations;
255             }
256         }
257 
258         /// <summary>
259         /// Table of all types extensions
260         /// </summary>
261         internal XmlSchemaObjectTable TypeExtensions {
262             get {
263                 if (typeExtensions == null) {
264                     typeExtensions = new XmlSchemaObjectTable();
265                 }
266                 return typeExtensions;
267             }
268         }
269 //Public Methods
270 
271         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Add1"]/*' />
272         /// <devdoc>
273         ///    <para>Add the schema located by the given URL into the schema schemas.
274         ///       If the given schema references other namespaces, the schemas for those other
275         ///       namespaces are NOT automatically loaded.</para>
276         /// </devdoc>
277         [ResourceConsumption(ResourceScope.Machine)]
278         [ResourceExposure(ResourceScope.Machine)]
279         public XmlSchema Add(String targetNamespace, String schemaUri) {
280             if (schemaUri == null || schemaUri.Length == 0) {
281                 throw new ArgumentNullException("schemaUri");
282             }
283             if (targetNamespace != null) {
284                 targetNamespace = XmlComplianceUtil.CDataNormalize(targetNamespace);
285             }
286             XmlSchema schema = null;
287             lock (InternalSyncObject) {
288                 //Check if schema from url has already been added
289                 XmlResolver tempResolver = readerSettings.GetXmlResolver();
290                 if ( tempResolver == null ) {
291                     tempResolver = new XmlUrlResolver();
292                 }
293                 Uri tempSchemaUri = tempResolver.ResolveUri(null, schemaUri);
294                 if (IsSchemaLoaded(tempSchemaUri, targetNamespace, out schema)) {
295                     return schema;
296                 }
297                 else {
298                     //Url already not processed; Load SOM from url
299                     XmlReader reader = XmlReader.Create(schemaUri, readerSettings);
300                     try {
301                         schema = Add(targetNamespace, ParseSchema(targetNamespace, reader)); //
302                         while(reader.Read());// wellformness check;
303                     }
304                     finally {
305                         reader.Close();
306                     }
307                 }
308             }
309             return schema;
310         }
311 
312 
313         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Add4"]/*' />
314         /// <devdoc>
315         ///    <para>Add the given schema into the schema schemas.
316         ///       If the given schema references other namespaces, the schemas for those
317         ///       other namespaces are NOT automatically loaded.</para>
318         /// </devdoc>
319         public XmlSchema Add(String targetNamespace, XmlReader schemaDocument) {
320             if (schemaDocument == null) {
321                 throw new ArgumentNullException("schemaDocument");
322             }
323             if (targetNamespace != null) {
324                 targetNamespace = XmlComplianceUtil.CDataNormalize(targetNamespace);
325             }
326             lock (InternalSyncObject) {
327                 XmlSchema schema = null;
328                 Uri schemaUri = new Uri(schemaDocument.BaseURI, UriKind.RelativeOrAbsolute);
329                 if (IsSchemaLoaded(schemaUri, targetNamespace, out schema)) {
330                     return schema;
331                 }
332                 else {
333                     DtdProcessing dtdProcessing = this.readerSettings.DtdProcessing;
334                     SetDtdProcessing(schemaDocument);
335                     schema = Add(targetNamespace, ParseSchema(targetNamespace, schemaDocument));
336                     this.readerSettings.DtdProcessing = dtdProcessing; //reset dtdProcessing setting
337                     return schema;
338                 }
339             }
340         }
341 
342 
343         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Add5"]/*' />
344         /// <devdoc>
345         ///    <para>Adds all the namespaces defined in the given schemas
346         ///       (including their associated schemas) to this schemas.</para>
347         /// </devdoc>
348         public void Add(XmlSchemaSet schemas) {
349             if (schemas == null) {
350                 throw new ArgumentNullException("schemas");
351             }
352             if (this == schemas) {
353                 return;
354             }
355             bool thisLockObtained = false;
356             bool schemasLockObtained = false;
357             try {
358                 while(true) {
359                     Monitor.TryEnter(InternalSyncObject, ref thisLockObtained);
360                     if (thisLockObtained) {
361                         Monitor.TryEnter(schemas.InternalSyncObject, ref schemasLockObtained);
362                         if (schemasLockObtained) {
363                             break;
364                         }
365                         else {
366                             Monitor.Exit(InternalSyncObject); //Give up this lock and try both again
367                             thisLockObtained = false;
368                             Thread.Yield(); //Let the thread that holds the lock run
369                             continue;
370                         }
371                     }
372                 }
373 
374                 XmlSchema currentSchema;
375                 //
376                 if (schemas.IsCompiled) {
377                     CopyFromCompiledSet(schemas);
378                 }
379                 else {
380                     bool remove = false;
381                     string tns = null;
382                     foreach(XmlSchema schema in schemas.SortedSchemas.Values) {
383                         tns = schema.TargetNamespace;
384                         if (tns == null) {
385                             tns = string.Empty;
386                         }
387                         if (this.schemas.ContainsKey(schema.SchemaId) || FindSchemaByNSAndUrl(schema.BaseUri, tns, null) != null) { //Do not already existing url
388                             continue;
389                         }
390                         currentSchema = Add(schema.TargetNamespace, schema);
391                         if(currentSchema == null) {
392                             remove = true;
393                             break;
394                         }
395                     }
396                     //Remove all from the set if even one schema in the passed in set is not preprocessed.
397                     if (remove) {
398                         foreach(XmlSchema schema in schemas.SortedSchemas.Values) { //Remove all previously added schemas from the set
399                             this.schemas.Remove(schema.SchemaId); //Might remove schema that was already there and was not added thru this operation
400                             schemaLocations.Remove(schema.BaseUri);
401                         }
402                     }
403                 }
404             }
405             finally { //release locks on sets
406                 if (thisLockObtained) {
407                     Monitor.Exit(InternalSyncObject);
408                 }
409                 if (schemasLockObtained) {
410                     Monitor.Exit(schemas.InternalSyncObject);
411                 }
412             }
413         }
414 
415         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Add6"]/*' />
416         public XmlSchema Add(XmlSchema schema) {
417             if (schema == null) {
418                 throw new ArgumentNullException("schema");
419             }
420             lock (InternalSyncObject) {
421                 if (schemas.ContainsKey(schema.SchemaId)) {
422                     return schema;
423                 }
424                 return Add(schema.TargetNamespace, schema);
425             }
426         }
427 
428         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Remove"]/*' />
429         public XmlSchema Remove(XmlSchema schema) {
430             return Remove(schema, true);
431         }
432 
433         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.RemoveRecursive"]/*' />
434         public bool RemoveRecursive(XmlSchema schemaToRemove) {
435 
436             if (schemaToRemove == null) {
437                 throw new ArgumentNullException("schemaToRemove");
438             }
439             if (!schemas.ContainsKey(schemaToRemove.SchemaId)) {
440                 return false;
441             }
442 
443             lock (InternalSyncObject) { //Need to lock here so that remove cannot be called while the set is being compiled
444                 if (schemas.ContainsKey(schemaToRemove.SchemaId)) { //Need to check again
445 
446                     //Build disallowedNamespaces list
447                     Hashtable disallowedNamespaces = new Hashtable();
448                     disallowedNamespaces.Add(GetTargetNamespace(schemaToRemove), schemaToRemove);
449                     string importedNS;
450                     for (int i = 0; i < schemaToRemove.ImportedNamespaces.Count; i++) {
451                         importedNS = (string)schemaToRemove.ImportedNamespaces[i];
452                         if (disallowedNamespaces[importedNS] == null) {
453                             disallowedNamespaces.Add(importedNS, importedNS);
454                         }
455                     }
456 
457                     //Removal list is all schemas imported by this schema directly or indirectly
458                     //Need to check if other schemas in the set import schemaToRemove / any of its imports
459                     ArrayList needToCheckSchemaList = new ArrayList();
460                     XmlSchema mainSchema;
461                     for (int i =0; i < schemas.Count; i++) {
462                         mainSchema = (XmlSchema)schemas.GetByIndex(i);
463                         if (mainSchema == schemaToRemove ||
464                             schemaToRemove.ImportedSchemas.Contains(mainSchema)) {
465                             continue;
466                         }
467                         needToCheckSchemaList.Add(mainSchema);
468                     }
469 
470                     mainSchema = null;
471                     for (int i = 0; i < needToCheckSchemaList.Count; i++) { //Perf: Not using nested foreach here
472                         mainSchema = (XmlSchema)needToCheckSchemaList[i];
473 
474                         if (mainSchema.ImportedNamespaces.Count > 0) {
475                             foreach(string tns in disallowedNamespaces.Keys) {
476                                 if (mainSchema.ImportedNamespaces.Contains(tns)) {
477                                     SendValidationEvent(new XmlSchemaException(Res.Sch_SchemaNotRemoved, string.Empty), XmlSeverityType.Warning);
478                                     return false;
479                                 }
480                             }
481                         }
482                     }
483 
484                     Remove(schemaToRemove, true);
485                     for (int i = 0; i < schemaToRemove.ImportedSchemas.Count; ++i) {
486                         XmlSchema impSchema = (XmlSchema)schemaToRemove.ImportedSchemas[i];
487                         Remove(impSchema, true);
488                     }
489                     return true;
490                 }
491             }
492             return false;
493         }
494 
495         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Contains1"]/*' />
496         public bool Contains(String targetNamespace) {
497            if (targetNamespace == null) {
498                targetNamespace = string.Empty;
499            }
500            return targetNamespaces[targetNamespace] != null;
501         }
502 
503         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Contains2"]/*' />
504         public bool Contains(XmlSchema schema) {
505             if (schema == null) {
506                 throw new ArgumentNullException("schema");
507             }
508             return schemas.ContainsValue(schema);
509         }
510 
511         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Compile"]/*' />
512         /// <devdoc>
513         ///    <para>[To be supplied.]</para>
514         /// </devdoc>
515         public void Compile() {
516             if (isCompiled) {
517                 return;
518             }
519             if (schemas.Count == 0) {
520                 ClearTables(); //Clear any previously present compiled state left by calling just Remove() on the set
521                 cachedCompiledInfo = new SchemaInfo();
522                 isCompiled = true;
523                 compileAll = false;
524                 return;
525             }
526             lock (InternalSyncObject) {
527 
528                 if (!isCompiled) { //Locking before checking isCompiled to avoid problems with double locking
529                     Compiler compiler = new Compiler(nameTable, eventHandler, schemaForSchema, compilationSettings);
530                     SchemaInfo newCompiledInfo = new SchemaInfo();
531                     int schemaIndex = 0;
532                     if (!compileAll) { //if we are not compiling everything again, Move the pre-compiled schemas to the compiler's tables
533                         compiler.ImportAllCompiledSchemas(this);
534                     }
535                     try { //First thing to do in the try block is to acquire locks since finally will try to release them.
536                         //If we dont accuire the locks first, and an exception occurs in the code before the locking code, then Threading.SynchronizationLockException will be thrown
537                         //when attempting to release it in the finally block
538                         XmlSchema currentSchema;
539                         XmlSchema xmlNSSchema = Preprocessor.GetBuildInSchema();
540                         for (schemaIndex = 0; schemaIndex < schemas.Count; schemaIndex++) {
541                             currentSchema = (XmlSchema)schemas.GetByIndex(schemaIndex);
542 
543                             //Lock schema to be compiled
544 #pragma warning disable 0618
545                             //@
546                             Monitor.Enter(currentSchema);
547 #pragma warning restore 0618
548                             if (!currentSchema.IsPreprocessed)
549                             {
550                                 SendValidationEvent(new XmlSchemaException(Res.Sch_SchemaNotPreprocessed, string.Empty), XmlSeverityType.Error);
551                                 isCompiled = false;
552                                 return;
553                             }
554                             if (currentSchema.IsCompiledBySet) {
555                                 if (!compileAll) {
556                                     continue;
557                                 }
558                                 else if ((object)currentSchema == (object)xmlNSSchema) { // prepare for xml namespace schema without cleanup
559                                     compiler.Prepare(currentSchema, false);
560                                     continue;
561                                 }
562                             }
563                             compiler.Prepare(currentSchema, true);
564                         }
565 
566                         isCompiled = compiler.Execute(this, newCompiledInfo);
567                         if (isCompiled) {
568                             if (!compileAll) {
569                                 newCompiledInfo.Add(cachedCompiledInfo, eventHandler); //Add all the items from the old to the new compiled object
570                             }
571                             compileAll = false;
572                             cachedCompiledInfo = newCompiledInfo; //Replace the compiled info in the set after successful compilation
573                         }
574                     }
575                     finally {
576                         //Release locks on all schemas
577                         XmlSchema currentSchema;
578                         if (schemaIndex == schemas.Count) {
579                             schemaIndex--;
580                         }
581                         for (int i = schemaIndex; i >= 0; i--) {
582                             currentSchema = (XmlSchema)schemas.GetByIndex(i);
583                             if (currentSchema == Preprocessor.GetBuildInSchema()) { //dont re-set compiled flags for xml namespace schema
584                                 Monitor.Exit(currentSchema);
585                                 continue;
586                             }
587                             currentSchema.IsCompiledBySet = isCompiled;
588                             Monitor.Exit(currentSchema);
589                         }
590                     }
591                 }
592             }
593             return;
594         }
595 
596         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Reprocess"]/*' />
597         /// <devdoc>
598         ///    <para>[To be supplied.]</para>
599         /// </devdoc>
600         public XmlSchema Reprocess(XmlSchema schema) {
601             // Due to bug 644477 - this method is tightly coupled (THE CODE IS BASICALLY COPIED) to Remove, Add and AddSchemaToSet
602             // methods. If you change anything here *make sure* to update Remove/Add/AddSchemaToSet method(s) accordingly.
603             // The only difference is that we don't touch .schemas collection here to not break a code like this:
604             // foreach(XmlSchema s in schemaset.schemas) { schemaset.Reprocess(s); }
605             // This is by purpose.
606             if (schema == null) {
607                 throw new ArgumentNullException("schema");
608             }
609             if (!schemas.ContainsKey(schema.SchemaId)) {
610                 throw new ArgumentException(Res.GetString(Res.Sch_SchemaDoesNotExist), "schema");
611             }
612             XmlSchema originalSchema = schema;
613             lock (InternalSyncObject) { //Lock set so that set cannot be compiled in another thread
614 
615                 // This code is copied from method:
616                 // Remove(XmlSchema schema, bool forceCompile)
617                 // If you changed anything here go and change the same in Remove(XmlSchema schema, bool forceCompile) method
618                 #region Copied from Remove(XmlSchema schema, bool forceCompile)
619 
620                 RemoveSchemaFromGlobalTables(schema);
621                 RemoveSchemaFromCaches(schema);
622                 if (schema.BaseUri != null) {
623                     schemaLocations.Remove(schema.BaseUri);
624                 }
625                 string tns = GetTargetNamespace(schema);
626                 if (Schemas(tns).Count == 0) { //This is the only schema for that namespace
627                     targetNamespaces.Remove(tns);
628                 }
629                 isCompiled = false;
630                 compileAll = true; //Force compilation of the whole set; This is when the set is not completely thread-safe
631 
632                 #endregion //Copied from Remove(XmlSchema schema, bool forceCompile)
633 
634 
635                 // This code is copied from method:
636                 // Add(string targetNamespace, XmlSchema schema)
637                 // If you changed anything here go and change the same in Add(string targetNamespace, XmlSchema schema) method
638                 #region Copied from Add(string targetNamespace, XmlSchema schema)
639 
640                 if (schema.ErrorCount != 0) { //Schema with parsing errors cannot be loaded
641                     return originalSchema;
642                 }
643                 if (PreprocessSchema(ref schema, schema.TargetNamespace)) { //No perf opt for already compiled schemas
644 
645                     // This code is copied from method:
646                     // AddSchemaToSet(XmlSchema schema)
647                     // If you changed anything here go and change the same in AddSchemaToSet(XmlSchema schema) method
648                     #region Copied from AddSchemaToSet(XmlSchema schema)
649 
650                     //Add to targetNamespaces table
651                     if (targetNamespaces[tns] == null) {
652                         targetNamespaces.Add(tns, tns);
653                     }
654                     if (schemaForSchema == null && tns == XmlReservedNs.NsXs && schema.SchemaTypes[DatatypeImplementation.QnAnyType] != null) { //it has xs:anyType
655                         schemaForSchema = schema;
656                     }
657                     for (int i = 0; i < schema.ImportedSchemas.Count; ++i) {    //Once preprocessed external schemas property is set
658                         XmlSchema s = (XmlSchema)schema.ImportedSchemas[i];
659                         if (!schemas.ContainsKey(s.SchemaId)) {
660                             schemas.Add(s.SchemaId, s);
661                         }
662                         tns = GetTargetNamespace(s);
663                         if (targetNamespaces[tns] == null) {
664                             targetNamespaces.Add(tns, tns);
665                         }
666                         if (schemaForSchema == null && tns == XmlReservedNs.NsXs && schema.SchemaTypes[DatatypeImplementation.QnAnyType] != null) { //it has xs:anyType
667                             schemaForSchema = schema;
668                         }
669                     }
670                     #endregion //Copied from AddSchemaToSet(XmlSchema schema)
671                     return schema;
672                 }
673                 #endregion // Copied from Add(string targetNamespace, XmlSchema schema)
674 
675                 return originalSchema;
676             }
677         }
678 
679         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.CopyTo"]/*' />
680         /// <devdoc>
681         ///    <para>[To be supplied.]</para>
682         /// </devdoc>
683         public void CopyTo(XmlSchema[] schemas, int index) {
684             if (schemas == null)
685                 throw new ArgumentNullException("schemas");
686             if (index < 0 || index > schemas.Length -1 )
687                 throw new ArgumentOutOfRangeException("index");
688             this.schemas.Values.CopyTo(schemas, index);
689         }
690 
691         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Schemas1"]/*' />
692         /// <devdoc>
693         ///    <para>[To be supplied.]</para>
694         /// </devdoc>
695         public ICollection Schemas() {
696             return schemas.Values;
697         }
698 
699         /// <include file='doc\XmlSchemaSet.uex' path='docs/doc[@for="XmlSchemaSet.Schemas1"]/*' />
700         /// <devdoc>
701         ///    <para>[To be supplied.]</para>
702         /// </devdoc>
703         public ICollection Schemas(String targetNamespace) {
704             ArrayList tnsSchemas = new ArrayList();
705             XmlSchema currentSchema;
706             if (targetNamespace == null) {
707                 targetNamespace = string.Empty;
708             }
709             for (int i=0; i < schemas.Count; i++) {
710                 currentSchema = (XmlSchema)schemas.GetByIndex(i);
711                 if (GetTargetNamespace(currentSchema) == targetNamespace) {
712                     tnsSchemas.Add(currentSchema);
713                 }
714             }
715             return tnsSchemas;
716         }
717 
718 //Internal Methods
719 
720         private XmlSchema Add(string targetNamespace, XmlSchema schema) {
721             // Due to bug 644477 - this method is tightly coupled (THE CODE IS BASICALLY COPIED) to Reprocess
722             // method. If you change anything here *make sure* to update Reprocess method accordingly.
723 
724             if (schema == null || schema.ErrorCount != 0) { //Schema with parsing errors cannot be loaded
725                 return null;
726             }
727 
728             // This code is copied to method:
729             // Reprocess(XmlSchema schema)
730             // If you changed anything here go and change the same in Reprocess(XmlSchema schema) method
731             if (PreprocessSchema(ref schema, targetNamespace)) { //No perf opt for already compiled schemas
732                 AddSchemaToSet(schema);
733                 isCompiled = false;
734                 return schema;
735             }
736             return null;
737         }
738 
739 #if TRUST_COMPILE_STATE
740         private void AddCompiledSchema(XmlSchema schema) {
741             if (schema.IsCompiledBySet ) { //trust compiled state always if it is not a chameleon schema
742                 VerifyTables();
743                 SchemaInfo newCompiledInfo = new SchemaInfo();
744                 XmlSchemaObjectTable substitutionGroupsTable = null;
745                 if (!AddToCompiledInfo(schema, newCompiledInfo, ref substitutionGroupsTable)) { //Error while adding main schema
746                     return null;
747                 }
748                 foreach (XmlSchema impSchema in schema.ImportedSchemas) {
749                     if (!AddToCompiledInfo(impSchema, newCompiledInfo, ref substitutionGroupsTable)) { //Error while adding imports
750                         return null;
751                     }
752                 }
753                 newCompiledInfo.Add(cachedCompiledInfo, eventHandler); //Add existing compiled info
754                 cachedCompiledInfo = newCompiledInfo;
755                 if (substitutionGroupsTable != null) {
756                     ProcessNewSubstitutionGroups(substitutionGroupsTable, true);
757                 }
758                 if (schemas.Count == 0) { //If its the first compiled schema being added, then set doesnt need to be compiled
759                     isCompiled = true;
760                     compileAll = false;
761                 }
762                 AddSchemaToSet(schema);
763                 return schema;
764             }
765         }
766 
767         private bool AddToCompiledInfo(XmlSchema schema, SchemaInfo newCompiledInfo, ref XmlSchemaObjectTable substTable) {
768             //Add schema's compiled tables to the set
769             if (schema.BaseUri != null && schemaLocations[schema.BaseUri] == null) { //Update schemaLocations table
770                 schemaLocations.Add(schema.BaseUri, schema);
771             }
772 
773             foreach (XmlSchemaElement element in schema.Elements.Values) {
774                 if(!AddToTable(elements, element.QualifiedName, element)) {
775                     RemoveSchemaFromGlobalTables(schema);
776                     return false;
777                 }
778                 XmlQualifiedName head = element.SubstitutionGroup;
779                 if (!head.IsEmpty) {
780                     if (substTable == null) {
781                         substTable = new XmlSchemaObjectTable();
782                     }
783                     XmlSchemaSubstitutionGroup substitutionGroup = (XmlSchemaSubstitutionGroup)substTable[head];
784                     if (substitutionGroup == null) {
785                         substitutionGroup = new XmlSchemaSubstitutionGroup();
786                         substitutionGroup.Examplar = head;
787                         substTable.Add(head, substitutionGroup);
788                     }
789                     ArrayList members = substitutionGroup.Members;
790                     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
791                         members.Add(element);
792                     }
793                 }
794             }
795             foreach (XmlSchemaAttribute attribute in schema.Attributes.Values) {
796                 if (!AddToTable(attributes, attribute.QualifiedName, attribute)) {
797                     RemoveSchemaFromGlobalTables(schema);
798                     return false;
799                 }
800             }
801             foreach (XmlSchemaType schemaType in schema.SchemaTypes.Values) {
802                 if (!AddToTable(schemaTypes, schemaType.QualifiedName, schemaType)) {
803                     RemoveSchemaFromGlobalTables(schema);
804                     return false;
805                 }
806             }
807             schema.AddCompiledInfo(newCompiledInfo);
808 
809             return true;
810         }
811 #endif
812 
813         //For use by the validator when loading schemaLocations in the instance
814         internal void Add(String targetNamespace, XmlReader reader, Hashtable validatedNamespaces) {
815             if (reader == null) {
816                 throw new ArgumentNullException("reader");
817             }
818             if (targetNamespace == null) {
819                 targetNamespace = string.Empty;
820             }
821             if (validatedNamespaces[targetNamespace] != null) {
822                 if (FindSchemaByNSAndUrl(new Uri(reader.BaseURI, UriKind.RelativeOrAbsolute), targetNamespace, null) != null) {
823                     return;
824                 }
825                 else {
826                     throw new XmlSchemaException(Res.Sch_ComponentAlreadySeenForNS, targetNamespace);
827                 }
828             }
829 
830             //Not locking set as this will not be accessible outside the validator
831             XmlSchema schema;
832             if (IsSchemaLoaded(new Uri(reader.BaseURI, UriKind.RelativeOrAbsolute), targetNamespace, out schema)) {
833                 return;
834             }
835             else { //top-level schema not present for same url
836                 schema = ParseSchema(targetNamespace, reader);
837 
838                 //Store the previous locations
839                 DictionaryEntry[] oldLocations = new DictionaryEntry[schemaLocations.Count];
840                 schemaLocations.CopyTo(oldLocations, 0);
841 
842                 //Add to set
843                 Add(targetNamespace, schema);
844                 if (schema.ImportedSchemas.Count > 0) { //Check imports
845                     string tns;
846                     for (int i = 0; i < schema.ImportedSchemas.Count; ++i) {
847                         XmlSchema impSchema = (XmlSchema)schema.ImportedSchemas[i];
848                         tns = impSchema.TargetNamespace;
849                         if (tns == null) {
850                             tns = string.Empty;
851                         }
852                         if (validatedNamespaces[tns] != null && (FindSchemaByNSAndUrl(impSchema.BaseUri, tns, oldLocations) == null) ) {
853                             RemoveRecursive(schema);
854                             throw new XmlSchemaException(Res.Sch_ComponentAlreadySeenForNS, tns);
855                         }
856                     }
857                  }
858             }
859         }
860 
861         internal XmlSchema FindSchemaByNSAndUrl(Uri schemaUri, string ns, DictionaryEntry[] locationsTable) {
862             if (schemaUri == null || schemaUri.OriginalString.Length == 0) {
863                 return null;
864             }
865             XmlSchema schema = null;
866             if (locationsTable == null) {
867                 schema = (XmlSchema)schemaLocations[schemaUri];
868             }
869             else {
870                 for (int i = 0; i < locationsTable.Length; i++) {
871                     if (schemaUri.Equals(locationsTable[i].Key)) {
872                         schema = (XmlSchema)locationsTable[i].Value;
873                         break;
874                     }
875                 }
876             }
877             if (schema != null) {
878                 Debug.Assert(ns != null);
879                 string tns = schema.TargetNamespace == null ? string.Empty : schema.TargetNamespace;
880                 if (tns == ns) {
881                     return schema;
882                 }
883                 else if (tns == string.Empty) { //There could be a chameleon for same ns
884                     // It is OK to pass in the schema we have found so far, since it must have the schemaUri we're looking for
885                     // (we found it that way above) and it must be the original chameleon schema (the one without target ns)
886                     // as we don't add the chameleon copies into the locations tables above.
887                     Debug.Assert(schema.BaseUri.Equals(schemaUri));
888                     ChameleonKey cKey = new ChameleonKey(ns, schema);
889                     schema = (XmlSchema)chameleonSchemas[cKey]; //Need not clone if a schema for that namespace already exists
890                 }
891                 else {
892                     schema = null;
893                 }
894             }
895             return schema;
896         }
897 
898         private void SetDtdProcessing(XmlReader reader) {
899             if (reader.Settings != null) {
900                 this.readerSettings.DtdProcessing = reader.Settings.DtdProcessing;
901             }
902             else {
903                 XmlTextReader v1Reader = reader as XmlTextReader;
904                 if (v1Reader != null) {
905                    this.readerSettings.DtdProcessing = v1Reader.DtdProcessing;
906                 }
907             }
908         }
909 
910         private void AddSchemaToSet(XmlSchema schema) {
911             // Due to bug 644477 - this method is tightly coupled (THE CODE IS BASICALLY COPIED) to Reprocess
912             // method. If you change anything here *make sure* to update Reprocess method accordingly.
913 
914             schemas.Add(schema.SchemaId, schema);
915             //Add to targetNamespaces table
916 
917             // This code is copied to method:
918             // Reprocess(XmlSchema schema)
919             // If you changed anything here go and change the same in Reprocess(XmlSchema schema) method
920             #region This code is copied to Reprocess(XmlSchema schema) method
921 
922             string tns = GetTargetNamespace(schema);
923             if (targetNamespaces[tns] == null) {
924                 targetNamespaces.Add(tns, tns);
925             }
926             if (schemaForSchema == null && tns == XmlReservedNs.NsXs && schema.SchemaTypes[DatatypeImplementation.QnAnyType] != null) { //it has xs:anyType
927                 schemaForSchema = schema;
928             }
929             for (int i = 0; i < schema.ImportedSchemas.Count; ++i) {    //Once preprocessed external schemas property is set
930                 XmlSchema s = (XmlSchema)schema.ImportedSchemas[i];
931                 if (!schemas.ContainsKey(s.SchemaId)) {
932                     schemas.Add(s.SchemaId, s);
933                 }
934                 tns = GetTargetNamespace(s);
935                 if (targetNamespaces[tns] == null) {
936                     targetNamespaces.Add(tns, tns);
937                 }
938                 if (schemaForSchema == null && tns == XmlReservedNs.NsXs && schema.SchemaTypes[DatatypeImplementation.QnAnyType] != null) { //it has xs:anyType
939                     schemaForSchema = schema;
940                 }
941             }
942 
943             #endregion // This code is copied to Reprocess(XmlSchema schema) method
944         }
945 
946         private void ProcessNewSubstitutionGroups(XmlSchemaObjectTable substitutionGroupsTable, bool resolve) {
947             foreach(XmlSchemaSubstitutionGroup substGroup in substitutionGroupsTable.Values) {
948                 if (resolve) { //Resolve substitutionGroups within this schema
949                     ResolveSubstitutionGroup(substGroup, substitutionGroupsTable);
950                 }
951 
952                 //Add or Merge new substitutionGroups with those that already exist in the set
953                 XmlQualifiedName head = substGroup.Examplar;
954                 XmlSchemaSubstitutionGroup oldSubstGroup = (XmlSchemaSubstitutionGroup)substitutionGroups[head];
955                 if (oldSubstGroup != null) {
956                     for (int i = 0; i < substGroup.Members.Count; ++i) {
957                         if (!oldSubstGroup.Members.Contains(substGroup.Members[i])) {
958                             oldSubstGroup.Members.Add(substGroup.Members[i]);
959                         }
960                     }
961                 }
962                 else {
963                     AddToTable(substitutionGroups, head, substGroup);
964                 }
965             }
966         }
967 
968         private void ResolveSubstitutionGroup(XmlSchemaSubstitutionGroup substitutionGroup, XmlSchemaObjectTable substTable) {
969             List<XmlSchemaElement> newMembers = null;
970             XmlSchemaElement headElement = (XmlSchemaElement)elements[substitutionGroup.Examplar];
971             if (substitutionGroup.Members.Contains(headElement)) {// already checked
972                 return;
973             }
974             for (int i = 0; i < substitutionGroup.Members.Count; ++i) {
975                 XmlSchemaElement element = (XmlSchemaElement)substitutionGroup.Members[i];
976 
977                 //Chain to other head's that are members of this head's substGroup
978                 XmlSchemaSubstitutionGroup g = (XmlSchemaSubstitutionGroup)substTable[element.QualifiedName];
979                 if (g != null) {
980                     ResolveSubstitutionGroup(g, substTable);
981                     for (int j = 0; j < g.Members.Count; ++j) {
982                         XmlSchemaElement element1 = (XmlSchemaElement)g.Members[j];
983                         if (element1 != element) { //Exclude the head
984                             if (newMembers == null) {
985                                 newMembers = new List<XmlSchemaElement>();
986                             }
987                             newMembers.Add(element1);
988                         }
989                     }
990                 }
991             }
992             if (newMembers != null) {
993                 for (int i = 0; i < newMembers.Count; ++i) {
994                     substitutionGroup.Members.Add(newMembers[i]);
995                 }
996             }
997             substitutionGroup.Members.Add(headElement);
998         }
999 
1000         internal XmlSchema Remove(XmlSchema schema, bool forceCompile) {
1001             // Due to bug 644477 - this method is tightly coupled (THE CODE IS BASICALLY COPIED) to Reprocess
1002             // method. If you change anything here *make sure* to update Reprocess method accordingly.
1003             if (schema == null) {
1004                 throw new ArgumentNullException("schema");
1005             }
1006             lock (InternalSyncObject) { //Need to lock here so that remove cannot be called while the set is being compiled
1007                 if (schemas.ContainsKey(schema.SchemaId)) {
1008 
1009                     // This code is copied to method:
1010                     // Reprocess(XmlSchema schema)
1011                     // If you changed anything here go and change the same in Reprocess(XmlSchema schema) method
1012                     #region This code is copied to Reprocess(XmlSchema schema) method
1013 
1014                     if (forceCompile) {
1015                         RemoveSchemaFromGlobalTables(schema);
1016                         RemoveSchemaFromCaches(schema);
1017                     }
1018                     schemas.Remove(schema.SchemaId);
1019                     if (schema.BaseUri != null) {
1020                         schemaLocations.Remove(schema.BaseUri);
1021                     }
1022                     string tns = GetTargetNamespace(schema);
1023                     if (Schemas(tns).Count == 0) { //This is the only schema for that namespace
1024                         targetNamespaces.Remove(tns);
1025                     }
1026                     if (forceCompile) {
1027                         isCompiled = false;
1028                         compileAll = true; //Force compilation of the whole set; This is when the set is not completely thread-safe
1029                     }
1030                     return schema;
1031 
1032                     #endregion // This code is copied to Reprocess(XmlSchema schema) method
1033                 }
1034             }
1035             return null;
1036         }
1037 
1038         private void ClearTables() {
1039             GlobalElements.Clear();
1040             GlobalAttributes.Clear();
1041             GlobalTypes.Clear();
1042             SubstitutionGroups.Clear();
1043             TypeExtensions.Clear();
1044         }
1045 
1046         internal bool PreprocessSchema(ref XmlSchema schema, string targetNamespace) {
1047             Preprocessor prep = new Preprocessor(nameTable, GetSchemaNames(nameTable), eventHandler, compilationSettings);
1048             prep.XmlResolver = readerSettings.GetXmlResolver_CheckConfig();
1049             prep.ReaderSettings = readerSettings;
1050             prep.SchemaLocations = schemaLocations;
1051             prep.ChameleonSchemas = chameleonSchemas;
1052             bool hasErrors = prep.Execute(schema, targetNamespace, true);
1053             schema = prep.RootSchema; //For any root level chameleon cloned
1054             return hasErrors;
1055         }
1056 
1057         internal XmlSchema ParseSchema(string targetNamespace, XmlReader reader) {
1058             XmlNameTable readerNameTable = reader.NameTable;
1059             SchemaNames schemaNames = GetSchemaNames(readerNameTable);
1060             Parser parser = new Parser(SchemaType.XSD, readerNameTable, schemaNames, eventHandler);
1061             parser.XmlResolver = readerSettings.GetXmlResolver_CheckConfig();
1062             SchemaType schemaType;
1063             try {
1064                 schemaType = parser.Parse(reader, targetNamespace);
1065             }
1066             catch(XmlSchemaException e) {
1067                 SendValidationEvent(e, XmlSeverityType.Error);
1068                 return null;
1069             }
1070             return parser.XmlSchema;
1071         }
1072 
1073         internal void CopyFromCompiledSet(XmlSchemaSet otherSet) {
1074             XmlSchema currentSchema;
1075             SortedList copyFromList = otherSet.SortedSchemas;
1076             bool setIsCompiled = schemas.Count == 0 ? true : false;
1077             ArrayList existingSchemas = new ArrayList();
1078 
1079             SchemaInfo newCompiledInfo = new SchemaInfo();
1080             Uri baseUri;
1081             for(int i=0; i < copyFromList.Count; i++) {
1082                 currentSchema = (XmlSchema)copyFromList.GetByIndex(i);
1083                 baseUri = currentSchema.BaseUri;
1084                 if (schemas.ContainsKey(currentSchema.SchemaId) || (baseUri != null && baseUri.OriginalString.Length != 0 && schemaLocations[baseUri] != null)) {
1085                     existingSchemas.Add(currentSchema);
1086                     continue;
1087                 }
1088                 schemas.Add(currentSchema.SchemaId, currentSchema);
1089                 if (baseUri != null && baseUri.OriginalString.Length != 0) {
1090                     schemaLocations.Add(baseUri, currentSchema);
1091                 }
1092                 string tns = GetTargetNamespace(currentSchema);
1093                 if (targetNamespaces[tns] == null) {
1094                     targetNamespaces.Add(tns, tns);
1095                 }
1096             }
1097 
1098             VerifyTables();
1099             foreach (XmlSchemaElement element in otherSet.GlobalElements.Values) {
1100                 if(!AddToTable(elements, element.QualifiedName, element)) {
1101                     goto RemoveAll;
1102                 }
1103             }
1104             foreach (XmlSchemaAttribute attribute in otherSet.GlobalAttributes.Values) {
1105                 if (!AddToTable(attributes, attribute.QualifiedName, attribute)) {
1106                     goto RemoveAll;
1107                 }
1108             }
1109             foreach (XmlSchemaType schemaType in otherSet.GlobalTypes.Values) {
1110                 if (!AddToTable(schemaTypes, schemaType.QualifiedName, schemaType)) {
1111                     goto RemoveAll;
1112                 }
1113             }
1114             //
1115             ProcessNewSubstitutionGroups(otherSet.SubstitutionGroups, false);
1116 
1117             newCompiledInfo.Add(cachedCompiledInfo, eventHandler); //Add all the items from the old to the new compiled object
1118             newCompiledInfo.Add(otherSet.CompiledInfo,eventHandler); //
1119             cachedCompiledInfo = newCompiledInfo; //Replace the compiled info in the set after successful compilation
1120             if (setIsCompiled) {
1121                 isCompiled = true;
1122                 compileAll = false;
1123             }
1124             return;
1125 
1126             RemoveAll:
1127                 foreach (XmlSchema schemaToRemove in copyFromList.Values) {
1128                     if (!existingSchemas.Contains(schemaToRemove)) {
1129                         Remove(schemaToRemove, false);
1130                     }
1131                 }
1132                 foreach (XmlSchemaElement elementToRemove in otherSet.GlobalElements.Values) {
1133                     if(!existingSchemas.Contains((XmlSchema)elementToRemove.Parent)) {
1134                         elements.Remove(elementToRemove.QualifiedName);
1135                     }
1136                 }
1137                 foreach (XmlSchemaAttribute attributeToRemove in otherSet.GlobalAttributes.Values) {
1138                     if(!existingSchemas.Contains((XmlSchema)attributeToRemove.Parent)) {
1139                         attributes.Remove(attributeToRemove.QualifiedName);
1140                     }
1141                 }
1142                 foreach (XmlSchemaType schemaTypeToRemove in otherSet.GlobalTypes.Values) {
1143                     if(!existingSchemas.Contains((XmlSchema)schemaTypeToRemove.Parent)) {
1144                         schemaTypes.Remove(schemaTypeToRemove.QualifiedName);
1145                     }
1146                 }
1147         }
1148 
1149         internal SchemaInfo CompiledInfo {
1150             get {
1151                 return cachedCompiledInfo;
1152             }
1153         }
1154 
1155         internal XmlReaderSettings ReaderSettings {
1156             get {
1157                 return readerSettings;
1158             }
1159         }
1160 
1161         internal XmlResolver GetResolver() {
1162             return readerSettings.GetXmlResolver_CheckConfig();
1163         }
1164 
1165         internal ValidationEventHandler GetEventHandler() {
1166             return eventHandler;
1167         }
1168 
1169         internal SchemaNames GetSchemaNames(XmlNameTable nt) {
1170             if (nameTable != nt) {
1171                 return new SchemaNames(nt);
1172             }
1173             else {
1174                 if (schemaNames == null) {
1175                     schemaNames = new SchemaNames( nameTable );
1176                 }
1177                 return schemaNames;
1178             }
1179         }
1180 
1181         internal bool IsSchemaLoaded(Uri schemaUri, string targetNamespace, out XmlSchema schema) {
1182             schema = null;
1183             if (targetNamespace == null) {
1184                 targetNamespace = string.Empty;
1185             }
1186             if (GetSchemaByUri(schemaUri, out schema)) {
1187                 if (schemas.ContainsKey(schema.SchemaId) && (targetNamespace.Length == 0 || targetNamespace == schema.TargetNamespace)) { //schema is present in set
1188                     //Schema found
1189                 }
1190                 else if (schema.TargetNamespace == null) { //If schema not in set or namespace doesnt match, then it might be a chameleon
1191                     XmlSchema chameleonSchema = FindSchemaByNSAndUrl(schemaUri, targetNamespace, null);
1192                     if (chameleonSchema != null && schemas.ContainsKey(chameleonSchema.SchemaId)) {
1193                         schema = chameleonSchema;
1194                     }
1195                     else {
1196                         schema = Add(targetNamespace, schema);
1197                     }
1198                 }
1199                 else if (targetNamespace.Length != 0 && targetNamespace != schema.TargetNamespace) {
1200                     SendValidationEvent(new XmlSchemaException(Res.Sch_MismatchTargetNamespaceEx, new string[] { targetNamespace, schema.TargetNamespace }), XmlSeverityType.Error);
1201                     schema = null;
1202                 }
1203                 else {
1204                     //If here, schema not present in set but in loc and might be added in loc through an earlier include
1205                     //S.TNS != null && ( tns == null or tns == s.TNS)
1206                     AddSchemaToSet(schema);
1207                 }
1208                 return true; //Schema Found
1209            }
1210            return false;
1211         }
1212 
1213         internal bool GetSchemaByUri(Uri schemaUri, out XmlSchema schema) {
1214             schema = null;
1215             if (schemaUri == null || schemaUri.OriginalString.Length == 0) {
1216                 return false;
1217             }
1218             schema = (XmlSchema)schemaLocations[schemaUri];
1219             if (schema != null) {
1220                 return true;
1221             }
1222             return false;
1223         }
1224 
1225         internal string GetTargetNamespace(XmlSchema schema) {
1226             return schema.TargetNamespace == null ? string.Empty : schema.TargetNamespace;
1227         }
1228 
1229 
1230         internal SortedList SortedSchemas {
1231             get {
1232                 return schemas;
1233             }
1234         }
1235 
1236         internal bool CompileAll {
1237             get {
1238                 return compileAll;
1239             }
1240         }
1241 
1242 //Private Methods
1243         private void RemoveSchemaFromCaches(XmlSchema schema) {
1244             //Remove From ChameleonSchemas and schemaLocations cache
1245             List<XmlSchema> reprocessList = new List<XmlSchema>();
1246             schema.GetExternalSchemasList(reprocessList, schema);
1247             for (int i = 0; i < reprocessList.Count; ++i) { //Remove schema from schemaLocations & chameleonSchemas tables
1248                 if (reprocessList[i].BaseUri != null && reprocessList[i].BaseUri.OriginalString.Length != 0) {
1249                     schemaLocations.Remove(reprocessList[i].BaseUri);
1250                 }
1251                 //Remove from chameleon table
1252                 ICollection chameleonKeys = chameleonSchemas.Keys;
1253                 ArrayList removalList = new ArrayList();
1254                 foreach(ChameleonKey cKey in chameleonKeys) {
1255                     if (cKey.chameleonLocation.Equals(reprocessList[i].BaseUri)) {
1256                         // The key will have the originalSchema set to null if the location was not empty
1257                         //   otherwise we need to care about it as there may be more chameleon schemas without
1258                         //   a base URI and we want to remove only those which were created as a clone of the one
1259                         //   we're removing.
1260                         if (cKey.originalSchema == null || Ref.ReferenceEquals(cKey.originalSchema, reprocessList[i])) {
1261                             removalList.Add(cKey);
1262                         }
1263                     }
1264                 }
1265                 for (int j = 0; j < removalList.Count; ++j) {
1266                     chameleonSchemas.Remove(removalList[j]);
1267                 }
1268             }
1269         }
1270 
1271         private void RemoveSchemaFromGlobalTables(XmlSchema schema) {
1272             if (schemas.Count == 0) {
1273                 return;
1274             }
1275             VerifyTables();
1276             foreach (XmlSchemaElement elementToRemove in schema.Elements.Values) {
1277                 XmlSchemaElement elem = (XmlSchemaElement)elements[elementToRemove.QualifiedName];
1278                 if (elem == elementToRemove) {
1279                     elements.Remove(elementToRemove.QualifiedName);
1280                 }
1281             }
1282             foreach (XmlSchemaAttribute attributeToRemove in schema.Attributes.Values) {
1283                 XmlSchemaAttribute attr = (XmlSchemaAttribute)attributes[attributeToRemove.QualifiedName];
1284                 if (attr == attributeToRemove) {
1285                     attributes.Remove(attributeToRemove.QualifiedName);
1286                 }
1287             }
1288             foreach (XmlSchemaType schemaTypeToRemove in schema.SchemaTypes.Values) {
1289                 XmlSchemaType schemaType = (XmlSchemaType)schemaTypes[schemaTypeToRemove.QualifiedName];
1290                 if (schemaType == schemaTypeToRemove) {
1291                     schemaTypes.Remove(schemaTypeToRemove.QualifiedName);
1292                 }
1293             }
1294         }
1295         private bool AddToTable(XmlSchemaObjectTable table, XmlQualifiedName qname, XmlSchemaObject item) {
1296             if (qname.Name.Length == 0) {
1297                 return true;
1298             }
1299             XmlSchemaObject existingObject = (XmlSchemaObject)table[qname];
1300             if (existingObject != null) {
1301                 if (existingObject == item || existingObject.SourceUri == item.SourceUri) {
1302                     return true;
1303                 }
1304                 string code = string.Empty;
1305                 if (item is XmlSchemaComplexType) {
1306                     code = Res.Sch_DupComplexType;
1307                 }
1308                 else if (item is XmlSchemaSimpleType) {
1309                     code = Res.Sch_DupSimpleType;
1310                 }
1311                 else if (item is XmlSchemaElement) {
1312                     code = Res.Sch_DupGlobalElement;
1313                 }
1314                 else if (item is XmlSchemaAttribute) {
1315                     if (qname.Namespace == XmlReservedNs.NsXml) {
1316                         XmlSchema schemaForXmlNS = Preprocessor.GetBuildInSchema();
1317                         XmlSchemaObject builtInAttribute = schemaForXmlNS.Attributes[qname];
1318                         if (existingObject == builtInAttribute) { //replace built-in one
1319                             table.Insert(qname, item);
1320                             return true;
1321                         }
1322                         else if (item == builtInAttribute) { //trying to overwrite customer's component with built-in, ignore built-in
1323                             return true;
1324                         }
1325                     }
1326                     code = Res.Sch_DupGlobalAttribute;
1327                 }
1328                 SendValidationEvent(new XmlSchemaException(code,qname.ToString()), XmlSeverityType.Error);
1329                 return false;
1330             }
1331             else {
1332                 table.Add(qname, item);
1333                 return true;
1334             }
1335         }
1336 
1337         private void VerifyTables() {
1338             if (elements == null) {
1339                 elements = new XmlSchemaObjectTable();
1340             }
1341             if (attributes == null) {
1342                 attributes = new XmlSchemaObjectTable();
1343             }
1344             if (schemaTypes == null) {
1345                 schemaTypes = new XmlSchemaObjectTable();
1346             }
1347             if (substitutionGroups == null) {
1348                 substitutionGroups = new XmlSchemaObjectTable();
1349             }
1350         }
1351 
1352         private void InternalValidationCallback(object sender, ValidationEventArgs e ) {
1353             if (e.Severity == XmlSeverityType.Error) {
1354                 throw e.Exception;
1355             }
1356         }
1357 
1358         private void SendValidationEvent(XmlSchemaException e, XmlSeverityType severity) {
1359             if (eventHandler != null) {
1360                 eventHandler(this, new ValidationEventArgs(e, severity));
1361             }
1362             else {
1363                 throw e;
1364             }
1365         }
1366     };
1367 #endif
1368 }
1369