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