1 /*
   2  * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved.
   3  * @LastModified: Nov 2017
   4  */
   5 /*
   6  * Licensed to the Apache Software Foundation (ASF) under one or more
   7  * contributor license agreements.  See the NOTICE file distributed with
   8  * this work for additional information regarding copyright ownership.
   9  * The ASF licenses this file to You under the Apache License, Version 2.0
  10  * (the "License"); you may not use this file except in compliance with
  11  * the License.  You may obtain a copy of the License at
  12  *
  13  *      http://www.apache.org/licenses/LICENSE-2.0
  14  *
  15  * Unless required by applicable law or agreed to in writing, software
  16  * distributed under the License is distributed on an "AS IS" BASIS,
  17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18  * See the License for the specific language governing permissions and
  19  * limitations under the License.
  20  */
  21 
  22 package com.sun.org.apache.xerces.internal.impl.xs;
  23 
  24 import com.sun.org.apache.xerces.internal.impl.Constants;
  25 import com.sun.org.apache.xerces.internal.impl.RevalidationHandler;
  26 import com.sun.org.apache.xerces.internal.impl.XMLEntityManager;
  27 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
  28 import com.sun.org.apache.xerces.internal.impl.dv.DatatypeException;
  29 import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeValueException;
  30 import com.sun.org.apache.xerces.internal.impl.dv.ValidatedInfo;
  31 import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType;
  32 import com.sun.org.apache.xerces.internal.impl.dv.xs.XSSimpleTypeDecl;
  33 import com.sun.org.apache.xerces.internal.impl.validation.ConfigurableValidationState;
  34 import com.sun.org.apache.xerces.internal.impl.validation.ValidationManager;
  35 import com.sun.org.apache.xerces.internal.impl.validation.ValidationState;
  36 import com.sun.org.apache.xerces.internal.impl.xs.identity.Field;
  37 import com.sun.org.apache.xerces.internal.impl.xs.identity.FieldActivator;
  38 import com.sun.org.apache.xerces.internal.impl.xs.identity.IdentityConstraint;
  39 import com.sun.org.apache.xerces.internal.impl.xs.identity.KeyRef;
  40 import com.sun.org.apache.xerces.internal.impl.xs.identity.Selector;
  41 import com.sun.org.apache.xerces.internal.impl.xs.identity.UniqueOrKey;
  42 import com.sun.org.apache.xerces.internal.impl.xs.identity.ValueStore;
  43 import com.sun.org.apache.xerces.internal.impl.xs.identity.XPathMatcher;
  44 import com.sun.org.apache.xerces.internal.impl.xs.models.CMBuilder;
  45 import com.sun.org.apache.xerces.internal.impl.xs.models.CMNodeFactory;
  46 import com.sun.org.apache.xerces.internal.impl.xs.models.XSCMValidator;
  47 import com.sun.org.apache.xerces.internal.impl.xs.util.XS10TypeHelper;
  48 import com.sun.org.apache.xerces.internal.parsers.XMLParser;
  49 import com.sun.org.apache.xerces.internal.util.AugmentationsImpl;
  50 import com.sun.org.apache.xerces.internal.util.IntStack;
  51 import com.sun.org.apache.xerces.internal.util.SymbolTable;
  52 import com.sun.org.apache.xerces.internal.util.URI.MalformedURIException;
  53 import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl;
  54 import com.sun.org.apache.xerces.internal.util.XMLChar;
  55 import com.sun.org.apache.xerces.internal.util.XMLSymbols;
  56 import com.sun.org.apache.xerces.internal.xni.Augmentations;
  57 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  58 import com.sun.org.apache.xerces.internal.xni.QName;
  59 import com.sun.org.apache.xerces.internal.xni.XMLAttributes;
  60 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler;
  61 import com.sun.org.apache.xerces.internal.xni.XMLLocator;
  62 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier;
  63 import com.sun.org.apache.xerces.internal.xni.XMLString;
  64 import com.sun.org.apache.xerces.internal.xni.XNIException;
  65 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription;
  66 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool;
  67 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent;
  68 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager;
  69 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException;
  70 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentFilter;
  71 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource;
  72 import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver;
  73 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource;
  74 import com.sun.org.apache.xerces.internal.xs.AttributePSVI;
  75 import com.sun.org.apache.xerces.internal.xs.ElementPSVI;
  76 import com.sun.org.apache.xerces.internal.xs.ShortList;
  77 import com.sun.org.apache.xerces.internal.xs.StringList;
  78 import com.sun.org.apache.xerces.internal.xs.XSConstants;
  79 import com.sun.org.apache.xerces.internal.xs.XSObjectList;
  80 import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
  81 import java.io.IOException;
  82 import java.util.ArrayList;
  83 import java.util.Collections;
  84 import java.util.HashMap;
  85 import java.util.Iterator;
  86 import java.util.List;
  87 import java.util.Map;
  88 import java.util.Stack;
  89 import java.util.Vector;
  90 import javax.xml.XMLConstants;
  91 import jdk.xml.internal.JdkXmlUtils;
  92 
  93 /**
  94  * The XML Schema validator. The validator implements a document
  95  * filter: receiving document events from the scanner; validating
  96  * the content and structure; augmenting the InfoSet, if applicable;
  97  * and notifying the parser of the information resulting from the
  98  * validation process.
  99  * <p>
 100  * This component requires the following features and properties from the
 101  * component manager that uses it:
 102  * <ul>
 103  *  <li>http://xml.org/sax/features/validation</li>
 104  *  <li>http://apache.org/xml/properties/internal/symbol-table</li>
 105  *  <li>http://apache.org/xml/properties/internal/error-reporter</li>
 106  *  <li>http://apache.org/xml/properties/internal/entity-resolver</li>
 107  * </ul>
 108  *
 109  * @xerces.internal
 110  *
 111  * @author Sandy Gao IBM
 112  * @author Elena Litani IBM
 113  * @author Andy Clark IBM
 114  * @author Neeraj Bajaj, Sun Microsystems, inc.
 115  */
 116 public class XMLSchemaValidator
 117     implements XMLComponent, XMLDocumentFilter, FieldActivator, RevalidationHandler, XSElementDeclHelper {
 118 
 119     //
 120     // Constants
 121     //
 122     private static final boolean DEBUG = false;
 123 
 124     // feature identifiers
 125 
 126     /** Feature identifier: validation. */
 127     protected static final String VALIDATION =
 128         Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE;
 129 
 130     /** Feature identifier: validation. */
 131     protected static final String SCHEMA_VALIDATION =
 132         Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE;
 133 
 134     /** Feature identifier: schema full checking*/
 135     protected static final String SCHEMA_FULL_CHECKING =
 136         Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_FULL_CHECKING;
 137 
 138     /** Feature identifier: dynamic validation. */
 139     protected static final String DYNAMIC_VALIDATION =
 140         Constants.XERCES_FEATURE_PREFIX + Constants.DYNAMIC_VALIDATION_FEATURE;
 141 
 142     /** Feature identifier: expose schema normalized value */
 143     protected static final String NORMALIZE_DATA =
 144         Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_NORMALIZED_VALUE;
 145 
 146     /** Feature identifier: send element default value via characters() */
 147     protected static final String SCHEMA_ELEMENT_DEFAULT =
 148         Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_ELEMENT_DEFAULT;
 149 
 150     /** Feature identifier: augment PSVI */
 151     protected static final String SCHEMA_AUGMENT_PSVI =
 152         Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_AUGMENT_PSVI;
 153 
 154     /** Feature identifier: whether to recognize java encoding names */
 155     protected static final String ALLOW_JAVA_ENCODINGS =
 156         Constants.XERCES_FEATURE_PREFIX + Constants.ALLOW_JAVA_ENCODINGS_FEATURE;
 157 
 158     /** Feature identifier: standard uri conformant feature. */
 159     protected static final String STANDARD_URI_CONFORMANT_FEATURE =
 160         Constants.XERCES_FEATURE_PREFIX + Constants.STANDARD_URI_CONFORMANT_FEATURE;
 161 
 162     /** Feature: generate synthetic annotations */
 163     protected static final String GENERATE_SYNTHETIC_ANNOTATIONS =
 164         Constants.XERCES_FEATURE_PREFIX + Constants.GENERATE_SYNTHETIC_ANNOTATIONS_FEATURE;
 165 
 166     /** Feature identifier: validate annotations. */
 167     protected static final String VALIDATE_ANNOTATIONS =
 168         Constants.XERCES_FEATURE_PREFIX + Constants.VALIDATE_ANNOTATIONS_FEATURE;
 169 
 170     /** Feature identifier: honour all schemaLocations */
 171     protected static final String HONOUR_ALL_SCHEMALOCATIONS =
 172         Constants.XERCES_FEATURE_PREFIX + Constants.HONOUR_ALL_SCHEMALOCATIONS_FEATURE;
 173 
 174     /** Feature identifier: use grammar pool only */
 175     protected static final String USE_GRAMMAR_POOL_ONLY =
 176         Constants.XERCES_FEATURE_PREFIX + Constants.USE_GRAMMAR_POOL_ONLY_FEATURE;
 177 
 178     /** Feature identifier: whether to continue parsing a schema after a fatal error is encountered */
 179     protected static final String CONTINUE_AFTER_FATAL_ERROR =
 180         Constants.XERCES_FEATURE_PREFIX + Constants.CONTINUE_AFTER_FATAL_ERROR_FEATURE;
 181 
 182     protected static final String PARSER_SETTINGS =
 183             Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS;
 184 
 185     /** Feature identifier: namespace growth */
 186     protected static final String NAMESPACE_GROWTH =
 187         Constants.XERCES_FEATURE_PREFIX + Constants.NAMESPACE_GROWTH_FEATURE;
 188 
 189     /** Feature identifier: tolerate duplicates */
 190     protected static final String TOLERATE_DUPLICATES =
 191         Constants.XERCES_FEATURE_PREFIX + Constants.TOLERATE_DUPLICATES_FEATURE;
 192 
 193     /** Feature identifier: whether to ignore xsi:type attributes until a global element declaration is encountered */
 194     protected static final String IGNORE_XSI_TYPE =
 195         Constants.XERCES_FEATURE_PREFIX + Constants.IGNORE_XSI_TYPE_FEATURE;
 196 
 197     /** Feature identifier: whether to ignore ID/IDREF errors */
 198     protected static final String ID_IDREF_CHECKING =
 199         Constants.XERCES_FEATURE_PREFIX + Constants.ID_IDREF_CHECKING_FEATURE;
 200 
 201     /** Feature identifier: whether to ignore unparsed entity errors */
 202     protected static final String UNPARSED_ENTITY_CHECKING =
 203         Constants.XERCES_FEATURE_PREFIX + Constants.UNPARSED_ENTITY_CHECKING_FEATURE;
 204 
 205     /** Feature identifier: whether to ignore identity constraint errors */
 206     protected static final String IDENTITY_CONSTRAINT_CHECKING =
 207         Constants.XERCES_FEATURE_PREFIX + Constants.IDC_CHECKING_FEATURE;
 208 
 209     protected static final String REPORT_WHITESPACE =
 210             Constants.SUN_SCHEMA_FEATURE_PREFIX + Constants.SUN_REPORT_IGNORED_ELEMENT_CONTENT_WHITESPACE;
 211 
 212     // property identifiers
 213 
 214     /** Property identifier: symbol table. */
 215     public static final String SYMBOL_TABLE =
 216         Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY;
 217 
 218     /** Property identifier: error reporter. */
 219     public static final String ERROR_REPORTER =
 220         Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY;
 221 
 222     /** Property identifier: entity resolver. */
 223     public static final String ENTITY_RESOLVER =
 224         Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_RESOLVER_PROPERTY;
 225 
 226     /** Property identifier: grammar pool. */
 227     public static final String XMLGRAMMAR_POOL =
 228         Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY;
 229 
 230     protected static final String VALIDATION_MANAGER =
 231         Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY;
 232 
 233     protected static final String ENTITY_MANAGER =
 234         Constants.XERCES_PROPERTY_PREFIX + Constants.ENTITY_MANAGER_PROPERTY;
 235 
 236     /** Property identifier: schema location. */
 237     protected static final String SCHEMA_LOCATION =
 238         Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_LOCATION;
 239 
 240     /** Property identifier: no namespace schema location. */
 241     protected static final String SCHEMA_NONS_LOCATION =
 242         Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_NONS_LOCATION;
 243 
 244     /** Property identifier: JAXP schema source. */
 245     protected static final String JAXP_SCHEMA_SOURCE =
 246         Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_SOURCE;
 247 
 248     /** Property identifier: JAXP schema language. */
 249     protected static final String JAXP_SCHEMA_LANGUAGE =
 250         Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE;
 251 
 252     /** Property identifier: root type definition. */
 253     protected static final String ROOT_TYPE_DEF =
 254         Constants.XERCES_PROPERTY_PREFIX + Constants.ROOT_TYPE_DEFINITION_PROPERTY;
 255 
 256     /** Property identifier: root element declaration. */
 257     protected static final String ROOT_ELEMENT_DECL =
 258         Constants.XERCES_PROPERTY_PREFIX + Constants.ROOT_ELEMENT_DECLARATION_PROPERTY;
 259 
 260     /** Property identifier: Schema DV Factory */
 261     protected static final String SCHEMA_DV_FACTORY =
 262         Constants.XERCES_PROPERTY_PREFIX + Constants.SCHEMA_DV_FACTORY_PROPERTY;
 263 
 264     /** Property identifier: Security property manager. */
 265     private static final String XML_SECURITY_PROPERTY_MANAGER =
 266             Constants.XML_SECURITY_PROPERTY_MANAGER;
 267 
 268     protected static final String USE_SERVICE_MECHANISM = Constants.ORACLE_FEATURE_SERVICE_MECHANISM;
 269 
 270     protected static final String USE_CATALOG = XMLConstants.USE_CATALOG;
 271 
 272     // recognized features and properties
 273 
 274     /** Recognized features. */
 275     private static final String[] RECOGNIZED_FEATURES =
 276         {
 277             VALIDATION,
 278             SCHEMA_VALIDATION,
 279             DYNAMIC_VALIDATION,
 280             SCHEMA_FULL_CHECKING,
 281             ALLOW_JAVA_ENCODINGS,
 282             CONTINUE_AFTER_FATAL_ERROR,
 283             STANDARD_URI_CONFORMANT_FEATURE,
 284             GENERATE_SYNTHETIC_ANNOTATIONS,
 285             VALIDATE_ANNOTATIONS,
 286             HONOUR_ALL_SCHEMALOCATIONS,
 287             USE_GRAMMAR_POOL_ONLY,
 288             IGNORE_XSI_TYPE,
 289             ID_IDREF_CHECKING,
 290             IDENTITY_CONSTRAINT_CHECKING,
 291             UNPARSED_ENTITY_CHECKING,
 292             NAMESPACE_GROWTH,
 293             TOLERATE_DUPLICATES,
 294             USE_SERVICE_MECHANISM,
 295             USE_CATALOG
 296         };
 297 
 298     /** Feature defaults. */
 299     private static final Boolean[] FEATURE_DEFAULTS = { null,
 300         // NOTE: The following defaults are nulled out on purpose.
 301         //       If they are set, then when the XML Schema validator
 302         //       is constructed dynamically, these values may override
 303         //       those set by the application. This goes against the
 304         //       whole purpose of XMLComponent#getFeatureDefault but
 305         //       it can't be helped in this case. -Ac
 306         // NOTE: Instead of adding default values here, add them (and
 307         //       the corresponding recognized features) to the objects
 308         //       that have an XMLSchemaValidator instance as a member,
 309         //       such as the parser configurations. -PM
 310         null, //Boolean.FALSE,
 311         null, //Boolean.FALSE,
 312         null, //Boolean.FALSE,
 313         null, //Boolean.FALSE,
 314         null, //Boolean.FALSE,
 315         null,
 316         null,
 317         null,
 318         null,
 319         null,
 320         null,
 321         null,
 322         null,
 323         null,
 324         null,
 325         null,
 326         Boolean.TRUE,
 327         JdkXmlUtils.USE_CATALOG_DEFAULT
 328     };
 329 
 330     /** Recognized properties. */
 331     private static final String[] RECOGNIZED_PROPERTIES =
 332         {
 333             SYMBOL_TABLE,
 334             ERROR_REPORTER,
 335             ENTITY_RESOLVER,
 336             VALIDATION_MANAGER,
 337             SCHEMA_LOCATION,
 338             SCHEMA_NONS_LOCATION,
 339             JAXP_SCHEMA_SOURCE,
 340             JAXP_SCHEMA_LANGUAGE,
 341             ROOT_TYPE_DEF,
 342             ROOT_ELEMENT_DECL,
 343             SCHEMA_DV_FACTORY,
 344             XML_SECURITY_PROPERTY_MANAGER,
 345             JdkXmlUtils.CATALOG_DEFER,
 346             JdkXmlUtils.CATALOG_FILES,
 347             JdkXmlUtils.CATALOG_PREFER,
 348             JdkXmlUtils.CATALOG_RESOLVE,
 349             JdkXmlUtils.CDATA_CHUNK_SIZE
 350         };
 351 
 352     /** Property defaults. */
 353     private static final Object[] PROPERTY_DEFAULTS =
 354         { null, null, null, null, null, null, null, null, null, null, null, null,
 355             null, null, null, null, JdkXmlUtils.CDATA_CHUNK_SIZE_DEFAULT };
 356 
 357     // this is the number of valuestores of each kind
 358     // we expect an element to have.  It's almost
 359     // never > 1; so leave it at that.
 360     protected static final int ID_CONSTRAINT_NUM = 1;
 361 
 362     // xsi:* attribute declarations
 363     static final XSAttributeDecl XSI_TYPE =
 364             SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_TYPE);
 365     static final XSAttributeDecl XSI_NIL =
 366             SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_NIL);
 367     static final XSAttributeDecl XSI_SCHEMALOCATION =
 368             SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_SCHEMALOCATION);
 369     static final XSAttributeDecl XSI_NONAMESPACESCHEMALOCATION =
 370             SchemaGrammar.SG_XSI.getGlobalAttributeDecl(SchemaSymbols.XSI_NONAMESPACESCHEMALOCATION);
 371 
 372     //
 373     // Data
 374     //
 375 
 376     /** current PSVI element info */
 377     protected ElementPSVImpl fCurrentPSVI = new ElementPSVImpl();
 378 
 379     // since it is the responsibility of each component to an
 380     // Augmentations parameter if one is null, to save ourselves from
 381     // having to create this object continually, it is created here.
 382     // If it is not present in calls that we're passing on, we *must*
 383     // clear this before we introduce it into the pipeline.
 384     protected final AugmentationsImpl fAugmentations = new AugmentationsImpl();
 385 
 386     // this is included for the convenience of handleEndElement
 387     protected XMLString fDefaultValue;
 388 
 389     // Validation features
 390     protected boolean fDynamicValidation = false;
 391     protected boolean fSchemaDynamicValidation = false;
 392     protected boolean fDoValidation = false;
 393     protected boolean fFullChecking = false;
 394     protected boolean fNormalizeData = true;
 395     protected boolean fSchemaElementDefault = true;
 396     protected boolean fAugPSVI = true;
 397     protected boolean fIdConstraint = false;
 398     protected boolean fUseGrammarPoolOnly = false;
 399 
 400     // Namespace growth feature
 401     protected boolean fNamespaceGrowth = false;
 402 
 403     /** Schema type: None, DTD, Schema */
 404     private String fSchemaType = null;
 405 
 406     // to indicate whether we are in the scope of entity reference or CData
 407     protected boolean fEntityRef = false;
 408     protected boolean fInCDATA = false;
 409 
 410     // Did we see only whitespace in element content?
 411     protected boolean fSawOnlyWhitespaceInElementContent = false;
 412 
 413     // properties
 414 
 415     /** Symbol table. */
 416     protected SymbolTable fSymbolTable;
 417 
 418     /**
 419      * While parsing a document, keep the location of the document.
 420      */
 421     private XMLLocator fLocator;
 422 
 423     /**
 424      * A wrapper of the standard error reporter. We'll store all schema errors
 425      * in this wrapper object, so that we can get all errors (error codes) of
 426      * a specific element. This is useful for PSVI.
 427      */
 428     protected final class XSIErrorReporter {
 429 
 430         // the error reporter property
 431         XMLErrorReporter fErrorReporter;
 432 
 433         // store error codes; starting position of the errors for each element;
 434         // number of element (depth); and whether to record error
 435         Vector<String> fErrors = new Vector<>();
 436         int[] fContext = new int[INITIAL_STACK_SIZE];
 437         int fContextCount;
 438 
 439         // set the external error reporter, clear errors
 440         public void reset(XMLErrorReporter errorReporter) {
 441             fErrorReporter = errorReporter;
 442             fErrors.removeAllElements();
 443             fContextCount = 0;
 444         }
 445 
 446         // should be called when starting process an element or an attribute.
 447         // store the starting position for the current context
 448         public void pushContext() {
 449             if (!fAugPSVI) {
 450                 return;
 451             }
 452             // resize array if necessary
 453             if (fContextCount == fContext.length) {
 454                 int newSize = fContextCount + INC_STACK_SIZE;
 455                 int[] newArray = new int[newSize];
 456                 System.arraycopy(fContext, 0, newArray, 0, fContextCount);
 457                 fContext = newArray;
 458             }
 459 
 460             fContext[fContextCount++] = fErrors.size();
 461         }
 462 
 463         // should be called on endElement: get all errors of the current element
 464         public String[] popContext() {
 465             if (!fAugPSVI) {
 466                 return null;
 467             }
 468             // get starting position of the current element
 469             int contextPos = fContext[--fContextCount];
 470             // number of errors of the current element
 471             int size = fErrors.size() - contextPos;
 472             // if no errors, return null
 473             if (size == 0)
 474                 return null;
 475             // copy errors from the list to an string array
 476             String[] errors = new String[size];
 477             for (int i = 0; i < size; i++) {
 478                 errors[i] = fErrors.get(contextPos + i);
 479             }
 480             // remove errors of the current element
 481             fErrors.setSize(contextPos);
 482             return errors;
 483         }
 484 
 485         // should be called when an attribute is done: get all errors of
 486         // this attribute, but leave the errors to the containing element
 487         // also called after an element was strictly assessed.
 488         public String[] mergeContext() {
 489             if (!fAugPSVI) {
 490                 return null;
 491             }
 492             // get starting position of the current element
 493             int contextPos = fContext[--fContextCount];
 494             // number of errors of the current element
 495             int size = fErrors.size() - contextPos;
 496             // if no errors, return null
 497             if (size == 0)
 498                 return null;
 499             // copy errors from the list to an string array
 500             String[] errors = new String[size];
 501             for (int i = 0; i < size; i++) {
 502                 errors[i] = fErrors.get(contextPos + i);
 503             }
 504             // don't resize the vector: leave the errors for this attribute
 505             // to the containing element
 506             return errors;
 507         }
 508 
 509         public void reportError(String domain, String key, Object[] arguments, short severity)
 510             throws XNIException {
 511             String message = fErrorReporter.reportError(domain, key, arguments, severity);
 512             if (fAugPSVI) {
 513                 fErrors.add(key);
 514                 fErrors.add(message);
 515             }
 516         } // reportError(String,String,Object[],short)
 517 
 518         public void reportError(
 519             XMLLocator location,
 520             String domain,
 521             String key,
 522             Object[] arguments,
 523             short severity)
 524             throws XNIException {
 525             String message = fErrorReporter.reportError(location, domain, key, arguments, severity);
 526             if (fAugPSVI) {
 527                 fErrors.add(key);
 528                 fErrors.add(message);
 529             }
 530         } // reportError(XMLLocator,String,String,Object[],short)
 531     }
 532 
 533     /** Error reporter. */
 534     protected final XSIErrorReporter fXSIErrorReporter = new XSIErrorReporter();
 535 
 536     /** Entity resolver */
 537     protected XMLEntityResolver fEntityResolver;
 538 
 539     // updated during reset
 540     protected ValidationManager fValidationManager = null;
 541     protected ConfigurableValidationState fValidationState = new ConfigurableValidationState();
 542     protected XMLGrammarPool fGrammarPool;
 543 
 544     // schema location property values
 545     protected String fExternalSchemas = null;
 546     protected String fExternalNoNamespaceSchema = null;
 547 
 548     //JAXP Schema Source property
 549     protected Object fJaxpSchemaSource = null;
 550 
 551     /** Schema Grammar Description passed,  to give a chance to application to supply the Grammar */
 552     protected final XSDDescription fXSDDescription = new XSDDescription();
 553     protected final Map<String, XMLSchemaLoader.LocationArray> fLocationPairs = new HashMap<>();
 554 
 555 
 556     // handlers
 557 
 558     /** Document handler. */
 559     protected XMLDocumentHandler fDocumentHandler;
 560 
 561     protected XMLDocumentSource fDocumentSource;
 562 
 563     boolean reportWhitespace = false;
 564 
 565     //
 566     // XMLComponent methods
 567     //
 568 
 569     /**
 570      * Returns a list of feature identifiers that are recognized by
 571      * this component. This method may return null if no features
 572      * are recognized by this component.
 573      */
 574     public String[] getRecognizedFeatures() {
 575         return RECOGNIZED_FEATURES.clone();
 576     } // getRecognizedFeatures():String[]
 577 
 578     /**
 579      * Sets the state of a feature. This method is called by the component
 580      * manager any time after reset when a feature changes state.
 581      * <p>
 582      * <strong>Note:</strong> Components should silently ignore features
 583      * that do not affect the operation of the component.
 584      *
 585      * @param featureId The feature identifier.
 586      * @param state     The state of the feature.
 587      *
 588      * @throws SAXNotRecognizedException The component should not throw
 589      *                                   this exception.
 590      * @throws SAXNotSupportedException The component should not throw
 591      *                                  this exception.
 592      */
 593     public void setFeature(String featureId, boolean state) throws XMLConfigurationException {
 594     } // setFeature(String,boolean)
 595 
 596     /**
 597      * Returns a list of property identifiers that are recognized by
 598      * this component. This method may return null if no properties
 599      * are recognized by this component.
 600      */
 601     public String[] getRecognizedProperties() {
 602         return RECOGNIZED_PROPERTIES.clone();
 603     } // getRecognizedProperties():String[]
 604 
 605     /**
 606      * Sets the value of a property. This method is called by the component
 607      * manager any time after reset when a property changes value.
 608      * <p>
 609      * <strong>Note:</strong> Components should silently ignore properties
 610      * that do not affect the operation of the component.
 611      *
 612      * @param propertyId The property identifier.
 613      * @param value      The value of the property.
 614      *
 615      * @throws SAXNotRecognizedException The component should not throw
 616      *                                   this exception.
 617      * @throws SAXNotSupportedException The component should not throw
 618      *                                  this exception.
 619      */
 620     public void setProperty(String propertyId, Object value) throws XMLConfigurationException {
 621         if (propertyId.equals(ROOT_TYPE_DEF)) {
 622             if (value == null) {
 623                 fRootTypeQName = null;
 624                 fRootTypeDefinition = null;
 625             }
 626             else if (value instanceof javax.xml.namespace.QName) {
 627                 fRootTypeQName = (javax.xml.namespace.QName) value;
 628                 fRootTypeDefinition = null;
 629             }
 630             else {
 631                 fRootTypeDefinition = (XSTypeDefinition) value;
 632                 fRootTypeQName = null;
 633             }
 634         }
 635         else if (propertyId.equals(ROOT_ELEMENT_DECL)) {
 636             if (value == null) {
 637                 fRootElementDeclQName = null;
 638                 fRootElementDeclaration = null;
 639             }
 640             else if (value instanceof javax.xml.namespace.QName) {
 641                 fRootElementDeclQName = (javax.xml.namespace.QName) value;
 642                 fRootElementDeclaration = null;
 643             }
 644             else {
 645                 fRootElementDeclaration = (XSElementDecl) value;
 646                 fRootElementDeclQName = null;
 647             }
 648         }
 649     } // setProperty(String,Object)
 650 
 651     /**
 652      * Returns the default state for a feature, or null if this
 653      * component does not want to report a default value for this
 654      * feature.
 655      *
 656      * @param featureId The feature identifier.
 657      *
 658      * @since Xerces 2.2.0
 659      */
 660     public Boolean getFeatureDefault(String featureId) {
 661         for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
 662             if (RECOGNIZED_FEATURES[i].equals(featureId)) {
 663                 return FEATURE_DEFAULTS[i];
 664             }
 665         }
 666         return null;
 667     } // getFeatureDefault(String):Boolean
 668 
 669     /**
 670      * Returns the default state for a property, or null if this
 671      * component does not want to report a default value for this
 672      * property.
 673      *
 674      * @param propertyId The property identifier.
 675      *
 676      * @since Xerces 2.2.0
 677      */
 678     public Object getPropertyDefault(String propertyId) {
 679         for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
 680             if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
 681                 return PROPERTY_DEFAULTS[i];
 682             }
 683         }
 684         return null;
 685     } // getPropertyDefault(String):Object
 686 
 687     //
 688     // XMLDocumentSource methods
 689     //
 690 
 691     /** Sets the document handler to receive information about the document. */
 692     public void setDocumentHandler(XMLDocumentHandler documentHandler) {
 693         fDocumentHandler = documentHandler;
 694 
 695         // Init reportWhitespace for this handler
 696         if (documentHandler instanceof XMLParser) {
 697             try {
 698                 reportWhitespace =
 699                     ((XMLParser) documentHandler).getFeature(REPORT_WHITESPACE);
 700             }
 701             catch (Exception e) {
 702                 reportWhitespace = false;
 703             }
 704         }
 705     } // setDocumentHandler(XMLDocumentHandler)
 706 
 707     /** Returns the document handler */
 708     public XMLDocumentHandler getDocumentHandler() {
 709         return fDocumentHandler;
 710     } // setDocumentHandler(XMLDocumentHandler)
 711 
 712     //
 713     // XMLDocumentHandler methods
 714     //
 715 
 716     /** Sets the document source */
 717     public void setDocumentSource(XMLDocumentSource source) {
 718         fDocumentSource = source;
 719     } // setDocumentSource
 720 
 721     /** Returns the document source */
 722     public XMLDocumentSource getDocumentSource() {
 723         return fDocumentSource;
 724     } // getDocumentSource
 725 
 726     /**
 727      * The start of the document.
 728      *
 729      * @param locator The system identifier of the entity if the entity
 730      *                 is external, null otherwise.
 731      * @param encoding The auto-detected IANA encoding name of the entity
 732      *                 stream. This value will be null in those situations
 733      *                 where the entity encoding is not auto-detected (e.g.
 734      *                 internal entities or a document entity that is
 735      *                 parsed from a java.io.Reader).
 736      * @param namespaceContext
 737      *                 The namespace context in effect at the
 738      *                 start of this document.
 739      *                 This object represents the current context.
 740      *                 Implementors of this class are responsible
 741      *                 for copying the namespace bindings from the
 742      *                 the current context (and its parent contexts)
 743      *                 if that information is important.
 744      * @param augs     Additional information that may include infoset augmentations
 745      *
 746      * @throws XNIException Thrown by handler to signal an error.
 747      */
 748     public void startDocument(
 749         XMLLocator locator,
 750         String encoding,
 751         NamespaceContext namespaceContext,
 752         Augmentations augs)
 753         throws XNIException {
 754 
 755         fValidationState.setNamespaceSupport(namespaceContext);
 756         fState4XsiType.setNamespaceSupport(namespaceContext);
 757         fState4ApplyDefault.setNamespaceSupport(namespaceContext);
 758         fLocator = locator;
 759 
 760         handleStartDocument(locator, encoding);
 761         // call handlers
 762         if (fDocumentHandler != null) {
 763             fDocumentHandler.startDocument(locator, encoding, namespaceContext, augs);
 764         }
 765 
 766     } // startDocument(XMLLocator,String)
 767 
 768     /**
 769      * Notifies of the presence of an XMLDecl line in the document. If
 770      * present, this method will be called immediately following the
 771      * startDocument call.
 772      *
 773      * @param version    The XML version.
 774      * @param encoding   The IANA encoding name of the document, or null if
 775      *                   not specified.
 776      * @param standalone The standalone value, or null if not specified.
 777      * @param augs     Additional information that may include infoset augmentations
 778      *
 779      * @throws XNIException Thrown by handler to signal an error.
 780      */
 781     public void xmlDecl(String version, String encoding, String standalone, Augmentations augs)
 782         throws XNIException {
 783 
 784         // call handlers
 785         if (fDocumentHandler != null) {
 786             fDocumentHandler.xmlDecl(version, encoding, standalone, augs);
 787         }
 788 
 789     } // xmlDecl(String,String,String)
 790 
 791     /**
 792      * Notifies of the presence of the DOCTYPE line in the document.
 793      *
 794      * @param rootElement The name of the root element.
 795      * @param publicId    The public identifier if an external DTD or null
 796      *                    if the external DTD is specified using SYSTEM.
 797      * @param systemId    The system identifier if an external DTD, null
 798      *                    otherwise.
 799      * @param augs     Additional information that may include infoset augmentations
 800      *
 801      * @throws XNIException Thrown by handler to signal an error.
 802      */
 803     public void doctypeDecl(
 804         String rootElement,
 805         String publicId,
 806         String systemId,
 807         Augmentations augs)
 808         throws XNIException {
 809 
 810         // call handlers
 811         if (fDocumentHandler != null) {
 812             fDocumentHandler.doctypeDecl(rootElement, publicId, systemId, augs);
 813         }
 814 
 815     } // doctypeDecl(String,String,String)
 816 
 817     /**
 818      * The start of an element.
 819      *
 820      * @param element    The name of the element.
 821      * @param attributes The element attributes.
 822      * @param augs     Additional information that may include infoset augmentations
 823      *
 824      * @throws XNIException Thrown by handler to signal an error.
 825      */
 826     public void startElement(QName element, XMLAttributes attributes, Augmentations augs)
 827         throws XNIException {
 828 
 829         Augmentations modifiedAugs = handleStartElement(element, attributes, augs);
 830         // call handlers
 831         if (fDocumentHandler != null) {
 832             fDocumentHandler.startElement(element, attributes, modifiedAugs);
 833         }
 834 
 835     } // startElement(QName,XMLAttributes, Augmentations)
 836 
 837     /**
 838      * An empty element.
 839      *
 840      * @param element    The name of the element.
 841      * @param attributes The element attributes.
 842      * @param augs     Additional information that may include infoset augmentations
 843      *
 844      * @throws XNIException Thrown by handler to signal an error.
 845      */
 846     public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs)
 847         throws XNIException {
 848 
 849         Augmentations modifiedAugs = handleStartElement(element, attributes, augs);
 850 
 851         // in the case where there is a {value constraint}, and the element
 852         // doesn't have any text content, change emptyElement call to
 853         // start + characters + end
 854         fDefaultValue = null;
 855         // fElementDepth == -2 indicates that the schema validator was removed
 856         // from the pipeline. then we don't need to call handleEndElement.
 857         if (fElementDepth != -2)
 858             modifiedAugs = handleEndElement(element, modifiedAugs);
 859 
 860         // call handlers
 861         if (fDocumentHandler != null) {
 862             if (!fSchemaElementDefault || fDefaultValue == null) {
 863                 fDocumentHandler.emptyElement(element, attributes, modifiedAugs);
 864             } else {
 865                 fDocumentHandler.startElement(element, attributes, modifiedAugs);
 866                 fDocumentHandler.characters(fDefaultValue, null);
 867                 fDocumentHandler.endElement(element, modifiedAugs);
 868             }
 869         }
 870     } // emptyElement(QName,XMLAttributes, Augmentations)
 871 
 872     /**
 873      * Character content.
 874      *
 875      * @param text The content.
 876      * @param augs     Additional information that may include infoset augmentations
 877      *
 878      * @throws XNIException Thrown by handler to signal an error.
 879      */
 880     public void characters(XMLString text, Augmentations augs) throws XNIException {
 881         text = handleCharacters(text);
 882 
 883         if (fSawOnlyWhitespaceInElementContent) {
 884             fSawOnlyWhitespaceInElementContent = false;
 885             if (!reportWhitespace) {
 886                 ignorableWhitespace(text, augs);
 887                 return;
 888             }
 889         }
 890 
 891         // call handlers
 892         if (fDocumentHandler != null) {
 893             if (fNormalizeData && fUnionType) {
 894                 // for union types we can't normalize data
 895                 // thus we only need to send augs information if any;
 896                 // the normalized data for union will be send
 897                 // after normalization is performed (at the endElement())
 898                 if (augs != null)
 899                     fDocumentHandler.characters(fEmptyXMLStr, augs);
 900             } else {
 901                 fDocumentHandler.characters(text, augs);
 902             }
 903         }
 904 
 905     } // characters(XMLString)
 906 
 907     /**
 908      * Ignorable whitespace. For this method to be called, the document
 909      * source must have some way of determining that the text containing
 910      * only whitespace characters should be considered ignorable. For
 911      * example, the validator can determine if a length of whitespace
 912      * characters in the document are ignorable based on the element
 913      * content model.
 914      *
 915      * @param text The ignorable whitespace.
 916      * @param augs     Additional information that may include infoset augmentations
 917      *
 918      * @throws XNIException Thrown by handler to signal an error.
 919      */
 920     public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException {
 921 
 922         handleIgnorableWhitespace(text);
 923         // call handlers
 924         if (fDocumentHandler != null) {
 925             fDocumentHandler.ignorableWhitespace(text, augs);
 926         }
 927 
 928     } // ignorableWhitespace(XMLString)
 929 
 930     /**
 931      * The end of an element.
 932      *
 933      * @param element The name of the element.
 934      * @param augs     Additional information that may include infoset augmentations
 935      *
 936      * @throws XNIException Thrown by handler to signal an error.
 937      */
 938     public void endElement(QName element, Augmentations augs) throws XNIException {
 939 
 940         // in the case where there is a {value constraint}, and the element
 941         // doesn't have any text content, add a characters call.
 942         fDefaultValue = null;
 943         Augmentations modifiedAugs = handleEndElement(element, augs);
 944         // call handlers
 945         if (fDocumentHandler != null) {
 946             if (!fSchemaElementDefault || fDefaultValue == null) {
 947                 fDocumentHandler.endElement(element, modifiedAugs);
 948             } else {
 949                 fDocumentHandler.characters(fDefaultValue, null);
 950                 fDocumentHandler.endElement(element, modifiedAugs);
 951             }
 952         }
 953     } // endElement(QName, Augmentations)
 954 
 955     /**
 956     * The start of a CDATA section.
 957     *
 958     * @param augs     Additional information that may include infoset augmentations
 959     *
 960     * @throws XNIException Thrown by handler to signal an error.
 961     */
 962     public void startCDATA(Augmentations augs) throws XNIException {
 963 
 964         // REVISIT: what should we do here if schema normalization is on??
 965         fInCDATA = true;
 966         // call handlers
 967         if (fDocumentHandler != null) {
 968             fDocumentHandler.startCDATA(augs);
 969         }
 970 
 971     } // startCDATA()
 972 
 973     /**
 974      * The end of a CDATA section.
 975      *
 976      * @param augs     Additional information that may include infoset augmentations
 977      *
 978      * @throws XNIException Thrown by handler to signal an error.
 979      */
 980     public void endCDATA(Augmentations augs) throws XNIException {
 981 
 982         // call handlers
 983         fInCDATA = false;
 984         if (fDocumentHandler != null) {
 985             fDocumentHandler.endCDATA(augs);
 986         }
 987 
 988     } // endCDATA()
 989 
 990     /**
 991      * The end of the document.
 992      *
 993      * @param augs     Additional information that may include infoset augmentations
 994      *
 995      * @throws XNIException Thrown by handler to signal an error.
 996      */
 997     public void endDocument(Augmentations augs) throws XNIException {
 998 
 999         handleEndDocument();
1000 
1001         // call handlers
1002         if (fDocumentHandler != null) {
1003             fDocumentHandler.endDocument(augs);
1004         }
1005         fLocator = null;
1006 
1007     } // endDocument(Augmentations)
1008 
1009     //
1010     // DOMRevalidationHandler methods
1011     //
1012 
1013 
1014 
1015 
1016 
1017     public boolean characterData(String data, Augmentations augs) {
1018 
1019         fSawText = fSawText || data.length() > 0;
1020 
1021         // REVISIT: this methods basically duplicates implementation of
1022         //          handleCharacters(). We should be able to reuse some code
1023 
1024         // if whitespace == -1 skip normalization, because it is a complexType
1025         // or a union type.
1026         if (fNormalizeData && fWhiteSpace != -1 && fWhiteSpace != XSSimpleType.WS_PRESERVE) {
1027             // normalize data
1028             normalizeWhitespace(data, fWhiteSpace == XSSimpleType.WS_COLLAPSE);
1029             fBuffer.append(fNormalizedStr.ch, fNormalizedStr.offset, fNormalizedStr.length);
1030         } else {
1031             if (fAppendBuffer)
1032                 fBuffer.append(data);
1033         }
1034 
1035         // When it's a complex type with element-only content, we need to
1036         // find out whether the content contains any non-whitespace character.
1037         boolean allWhiteSpace = true;
1038         if (fCurrentType != null
1039             && fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
1040             XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType;
1041             if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT) {
1042                 // data outside of element content
1043                 for (int i = 0; i < data.length(); i++) {
1044                     if (!XMLChar.isSpace(data.charAt(i))) {
1045                         allWhiteSpace = false;
1046                         fSawCharacters = true;
1047                         break;
1048                     }
1049                 }
1050             }
1051         }
1052 
1053         return allWhiteSpace;
1054     }
1055 
1056     public void elementDefault(String data) {
1057         // no-op
1058     }
1059 
1060     //
1061     // XMLDocumentHandler and XMLDTDHandler methods
1062     //
1063 
1064     /**
1065      * This method notifies the start of a general entity.
1066      * <p>
1067      * <strong>Note:</strong> This method is not called for entity references
1068      * appearing as part of attribute values.
1069      *
1070      * @param name     The name of the general entity.
1071      * @param identifier The resource identifier.
1072      * @param encoding The auto-detected IANA encoding name of the entity
1073      *                 stream. This value will be null in those situations
1074      *                 where the entity encoding is not auto-detected (e.g.
1075      *                 internal entities or a document entity that is
1076      *                 parsed from a java.io.Reader).
1077      * @param augs     Additional information that may include infoset augmentations
1078      *
1079      * @exception XNIException Thrown by handler to signal an error.
1080      */
1081     public void startGeneralEntity(
1082         String name,
1083         XMLResourceIdentifier identifier,
1084         String encoding,
1085         Augmentations augs)
1086         throws XNIException {
1087 
1088         // REVISIT: what should happen if normalize_data_ is on??
1089         fEntityRef = true;
1090         // call handlers
1091         if (fDocumentHandler != null) {
1092             fDocumentHandler.startGeneralEntity(name, identifier, encoding, augs);
1093         }
1094 
1095     } // startEntity(String,String,String,String,String)
1096 
1097     /**
1098      * Notifies of the presence of a TextDecl line in an entity. If present,
1099      * this method will be called immediately following the startEntity call.
1100      * <p>
1101      * <strong>Note:</strong> This method will never be called for the
1102      * document entity; it is only called for external general entities
1103      * referenced in document content.
1104      * <p>
1105      * <strong>Note:</strong> This method is not called for entity references
1106      * appearing as part of attribute values.
1107      *
1108      * @param version  The XML version, or null if not specified.
1109      * @param encoding The IANA encoding name of the entity.
1110      * @param augs     Additional information that may include infoset augmentations
1111      *
1112      * @throws XNIException Thrown by handler to signal an error.
1113      */
1114     public void textDecl(String version, String encoding, Augmentations augs) throws XNIException {
1115 
1116         // call handlers
1117         if (fDocumentHandler != null) {
1118             fDocumentHandler.textDecl(version, encoding, augs);
1119         }
1120 
1121     } // textDecl(String,String)
1122 
1123     /**
1124      * A comment.
1125      *
1126      * @param text The text in the comment.
1127      * @param augs     Additional information that may include infoset augmentations
1128      *
1129      * @throws XNIException Thrown by application to signal an error.
1130      */
1131     public void comment(XMLString text, Augmentations augs) throws XNIException {
1132 
1133         // call handlers
1134         if (fDocumentHandler != null) {
1135             fDocumentHandler.comment(text, augs);
1136         }
1137 
1138     } // comment(XMLString)
1139 
1140     /**
1141      * A processing instruction. Processing instructions consist of a
1142      * target name and, optionally, text data. The data is only meaningful
1143      * to the application.
1144      * <p>
1145      * Typically, a processing instruction's data will contain a series
1146      * of pseudo-attributes. These pseudo-attributes follow the form of
1147      * element attributes but are <strong>not</strong> parsed or presented
1148      * to the application as anything other than text. The application is
1149      * responsible for parsing the data.
1150      *
1151      * @param target The target.
1152      * @param data   The data or null if none specified.
1153      * @param augs     Additional information that may include infoset augmentations
1154      *
1155      * @throws XNIException Thrown by handler to signal an error.
1156      */
1157     public void processingInstruction(String target, XMLString data, Augmentations augs)
1158         throws XNIException {
1159 
1160         // call handlers
1161         if (fDocumentHandler != null) {
1162             fDocumentHandler.processingInstruction(target, data, augs);
1163         }
1164 
1165     } // processingInstruction(String,XMLString)
1166 
1167     /**
1168      * This method notifies the end of a general entity.
1169      * <p>
1170      * <strong>Note:</strong> This method is not called for entity references
1171      * appearing as part of attribute values.
1172      *
1173      * @param name   The name of the entity.
1174      * @param augs   Additional information that may include infoset augmentations
1175      *
1176      * @exception XNIException
1177      *                   Thrown by handler to signal an error.
1178      */
1179     public void endGeneralEntity(String name, Augmentations augs) throws XNIException {
1180 
1181         // call handlers
1182         fEntityRef = false;
1183         if (fDocumentHandler != null) {
1184             fDocumentHandler.endGeneralEntity(name, augs);
1185         }
1186 
1187     } // endEntity(String)
1188 
1189     // constants
1190 
1191     static final int INITIAL_STACK_SIZE = 8;
1192     static final int INC_STACK_SIZE = 8;
1193 
1194     //
1195     // Data
1196     //
1197 
1198     // Schema Normalization
1199 
1200     private static final boolean DEBUG_NORMALIZATION = false;
1201     // temporary empty string buffer.
1202     private final XMLString fEmptyXMLStr = new XMLString(null, 0, -1);
1203     // temporary character buffer, and empty string buffer.
1204     private static final int BUFFER_SIZE = 20;
1205     private final XMLString fNormalizedStr = new XMLString();
1206     private boolean fFirstChunk = true;
1207     // got first chunk in characters() (SAX)
1208     private boolean fTrailing = false; // Previous chunk had a trailing space
1209     private short fWhiteSpace = -1; //whiteSpace: preserve/replace/collapse
1210     private boolean fUnionType = false;
1211 
1212     /** Schema grammar resolver. */
1213     private final XSGrammarBucket fGrammarBucket = new XSGrammarBucket();
1214     private final SubstitutionGroupHandler fSubGroupHandler = new SubstitutionGroupHandler(this);
1215 
1216     /** the DV usd to convert xsi:type to a QName */
1217     // REVISIT: in new simple type design, make things in DVs static,
1218     //          so that we can QNameDV.getCompiledForm()
1219     private final XSSimpleType fQNameDV =
1220         (XSSimpleType) SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(SchemaSymbols.ATTVAL_QNAME);
1221 
1222     private final CMNodeFactory nodeFactory = new CMNodeFactory();
1223     /** used to build content models */
1224     // REVISIT: create decl pool, and pass it to each traversers
1225     private final CMBuilder fCMBuilder = new CMBuilder(nodeFactory);
1226 
1227     // Schema grammar loader
1228     private final XMLSchemaLoader fSchemaLoader =
1229         new XMLSchemaLoader(
1230                 fXSIErrorReporter.fErrorReporter,
1231                 fGrammarBucket,
1232                 fSubGroupHandler,
1233                 fCMBuilder);
1234 
1235     // state
1236 
1237     /** String representation of the validation root. */
1238     // REVISIT: what do we store here? QName, XPATH, some ID? use rawname now.
1239     private String fValidationRoot;
1240 
1241     /** Skip validation: anything below this level should be skipped */
1242     private int fSkipValidationDepth;
1243 
1244     /** anything above this level has validation_attempted != full */
1245     private int fNFullValidationDepth;
1246 
1247     /** anything above this level has validation_attempted != none */
1248     private int fNNoneValidationDepth;
1249 
1250     /** Element depth: -2: validator not in pipeline; >= -1 current depth. */
1251     private int fElementDepth;
1252 
1253     /** Seen sub elements. */
1254     private boolean fSubElement;
1255 
1256     /** Seen sub elements stack. */
1257     private boolean[] fSubElementStack = new boolean[INITIAL_STACK_SIZE];
1258 
1259     /** Current element declaration. */
1260     private XSElementDecl fCurrentElemDecl;
1261 
1262     /** Element decl stack. */
1263     private XSElementDecl[] fElemDeclStack = new XSElementDecl[INITIAL_STACK_SIZE];
1264 
1265     /** nil value of the current element */
1266     private boolean fNil;
1267 
1268     /** nil value stack */
1269     private boolean[] fNilStack = new boolean[INITIAL_STACK_SIZE];
1270 
1271     /** notation value of the current element */
1272     private XSNotationDecl fNotation;
1273 
1274     /** notation stack */
1275     private XSNotationDecl[] fNotationStack = new XSNotationDecl[INITIAL_STACK_SIZE];
1276 
1277     /** Current type. */
1278     private XSTypeDefinition fCurrentType;
1279 
1280     /** type stack. */
1281     private XSTypeDefinition[] fTypeStack = new XSTypeDefinition[INITIAL_STACK_SIZE];
1282 
1283     /** Current content model. */
1284     private XSCMValidator fCurrentCM;
1285 
1286     /** Content model stack. */
1287     private XSCMValidator[] fCMStack = new XSCMValidator[INITIAL_STACK_SIZE];
1288 
1289     /** the current state of the current content model */
1290     private int[] fCurrCMState;
1291 
1292     /** stack to hold content model states */
1293     private int[][] fCMStateStack = new int[INITIAL_STACK_SIZE][];
1294 
1295     /** whether the curret element is strictly assessed */
1296     private boolean fStrictAssess = true;
1297 
1298     /** strict assess stack */
1299     private boolean[] fStrictAssessStack = new boolean[INITIAL_STACK_SIZE];
1300 
1301     /** Temporary string buffers. */
1302     private final StringBuilder fBuffer = new StringBuilder();
1303 
1304     /** Whether need to append characters to fBuffer */
1305     private boolean fAppendBuffer = true;
1306 
1307     /** Did we see any character data? */
1308     private boolean fSawText = false;
1309 
1310     /** stack to record if we saw character data */
1311     private boolean[] fSawTextStack = new boolean[INITIAL_STACK_SIZE];
1312 
1313     /** Did we see non-whitespace character data? */
1314     private boolean fSawCharacters = false;
1315 
1316     /** Stack to record if we saw character data outside of element content*/
1317     private boolean[] fStringContent = new boolean[INITIAL_STACK_SIZE];
1318 
1319     /** temporary qname */
1320     private final QName fTempQName = new QName();
1321 
1322     /** value of the "root-type-definition" property. */
1323     private javax.xml.namespace.QName fRootTypeQName = null;
1324     private XSTypeDefinition fRootTypeDefinition = null;
1325 
1326     /** value of the "root-element-declaration" property. */
1327     private javax.xml.namespace.QName fRootElementDeclQName = null;
1328     private XSElementDecl fRootElementDeclaration = null;
1329 
1330     private int fIgnoreXSITypeDepth;
1331 
1332     private boolean fIDCChecking;
1333 
1334     /** temporary validated info */
1335     private ValidatedInfo fValidatedInfo = new ValidatedInfo();
1336 
1337     // used to validate default/fixed values against xsi:type
1338     // only need to check facets, so we set extraChecking to false (in reset)
1339     private ValidationState fState4XsiType = new ValidationState();
1340 
1341     // used to apply default/fixed values
1342     // only need to check id/idref/entity, so we set checkFacets to false
1343     private ValidationState fState4ApplyDefault = new ValidationState();
1344 
1345     // identity constraint information
1346 
1347     /**
1348      * Stack of active XPath matchers for identity constraints. All
1349      * active XPath matchers are notified of startElement
1350      * and endElement callbacks in order to perform their matches.
1351      * <p>
1352      * For each element with identity constraints, the selector of
1353      * each identity constraint is activated. When the selector matches
1354      * its XPath, then all the fields of the identity constraint are
1355      * activated.
1356      * <p>
1357      * <strong>Note:</strong> Once the activation scope is left, the
1358      * XPath matchers are automatically removed from the stack of
1359      * active matchers and no longer receive callbacks.
1360      */
1361     protected XPathMatcherStack fMatcherStack = new XPathMatcherStack();
1362 
1363     /** Cache of value stores for identity constraint fields. */
1364     protected ValueStoreCache fValueStoreCache = new ValueStoreCache();
1365 
1366     //
1367     // Constructors
1368     //
1369 
1370     /** Default constructor. */
1371     public XMLSchemaValidator() {
1372         fState4XsiType.setExtraChecking(false);
1373         fState4ApplyDefault.setFacetChecking(false);
1374 
1375     } // <init>()
1376 
1377     /*
1378      * Resets the component. The component can query the component manager
1379      * about any features and properties that affect the operation of the
1380      * component.
1381      *
1382      * @param componentManager The component manager.
1383      *
1384      * @throws SAXException Thrown by component on finitialization error.
1385      *                      For example, if a feature or property is
1386      *                      required for the operation of the component, the
1387      *                      component manager may throw a
1388      *                      SAXNotRecognizedException or a
1389      *                      SAXNotSupportedException.
1390      */
1391     public void reset(XMLComponentManager componentManager) throws XMLConfigurationException {
1392 
1393 
1394         fIdConstraint = false;
1395         //reset XSDDescription
1396         fLocationPairs.clear();
1397 
1398         // cleanup id table
1399         fValidationState.resetIDTables();
1400 
1401         // reset schema loader
1402         fSchemaLoader.reset(componentManager);
1403 
1404         // initialize state
1405         fCurrentElemDecl = null;
1406         fCurrentCM = null;
1407         fCurrCMState = null;
1408         fSkipValidationDepth = -1;
1409         fNFullValidationDepth = -1;
1410         fNNoneValidationDepth = -1;
1411         fElementDepth = -1;
1412         fSubElement = false;
1413         fSchemaDynamicValidation = false;
1414 
1415         // datatype normalization
1416         fEntityRef = false;
1417         fInCDATA = false;
1418 
1419         fMatcherStack.clear();
1420 
1421         // get error reporter
1422         fXSIErrorReporter.reset((XMLErrorReporter) componentManager.getProperty(ERROR_REPORTER));
1423 
1424         boolean parser_settings = componentManager.getFeature(PARSER_SETTINGS, true);
1425 
1426         if (!parser_settings) {
1427             // parser settings have not been changed
1428             fValidationManager.addValidationState(fValidationState);
1429             // the node limit on the SecurityManager may have changed so need to refresh.
1430             nodeFactory.reset();
1431             // Re-parse external schema location properties.
1432             XMLSchemaLoader.processExternalHints(
1433                 fExternalSchemas,
1434                 fExternalNoNamespaceSchema,
1435                 fLocationPairs,
1436                 fXSIErrorReporter.fErrorReporter);
1437             return;
1438         }
1439 
1440         // pass the component manager to the factory..
1441         nodeFactory.reset(componentManager);
1442 
1443         // get symbol table. if it's a new one, add symbols to it.
1444         SymbolTable symbolTable = (SymbolTable) componentManager.getProperty(SYMBOL_TABLE);
1445         if (symbolTable != fSymbolTable) {
1446             fSymbolTable = symbolTable;
1447         }
1448 
1449         fNamespaceGrowth = componentManager.getFeature(NAMESPACE_GROWTH, false);
1450         fDynamicValidation = componentManager.getFeature(DYNAMIC_VALIDATION, false);
1451 
1452         if (fDynamicValidation) {
1453             fDoValidation = true;
1454         } else {
1455             fDoValidation = componentManager.getFeature(VALIDATION, false);
1456         }
1457 
1458         if (fDoValidation) {
1459             fDoValidation |= componentManager.getFeature(XMLSchemaValidator.SCHEMA_VALIDATION, false);
1460         }
1461 
1462         fFullChecking = componentManager.getFeature(SCHEMA_FULL_CHECKING, false);
1463         fNormalizeData = componentManager.getFeature(NORMALIZE_DATA, false);
1464         fSchemaElementDefault = componentManager.getFeature(SCHEMA_ELEMENT_DEFAULT, false);
1465 
1466         fAugPSVI = componentManager.getFeature(SCHEMA_AUGMENT_PSVI, true);
1467 
1468         fSchemaType =
1469             (String) componentManager.getProperty(
1470                 Constants.JAXP_PROPERTY_PREFIX + Constants.SCHEMA_LANGUAGE, null);
1471 
1472         fUseGrammarPoolOnly = componentManager.getFeature(USE_GRAMMAR_POOL_ONLY, false);
1473 
1474         fEntityResolver = (XMLEntityResolver) componentManager.getProperty(ENTITY_MANAGER);
1475 
1476         fValidationManager = (ValidationManager) componentManager.getProperty(VALIDATION_MANAGER);
1477         fValidationManager.addValidationState(fValidationState);
1478         fValidationState.setSymbolTable(fSymbolTable);
1479 
1480         try {
1481             final Object rootType = componentManager.getProperty(ROOT_TYPE_DEF);
1482             if (rootType == null) {
1483                 fRootTypeQName = null;
1484                 fRootTypeDefinition = null;
1485             }
1486             else if (rootType instanceof javax.xml.namespace.QName) {
1487                 fRootTypeQName = (javax.xml.namespace.QName) rootType;
1488                 fRootTypeDefinition = null;
1489             }
1490             else {
1491                 fRootTypeDefinition = (XSTypeDefinition) rootType;
1492                 fRootTypeQName = null;
1493             }
1494         }
1495         catch (XMLConfigurationException e) {
1496             fRootTypeQName = null;
1497             fRootTypeDefinition = null;
1498         }
1499 
1500         try {
1501             final Object rootDecl = componentManager.getProperty(ROOT_ELEMENT_DECL);
1502             if (rootDecl == null) {
1503                 fRootElementDeclQName = null;
1504                 fRootElementDeclaration = null;
1505             }
1506             else if (rootDecl instanceof javax.xml.namespace.QName) {
1507                 fRootElementDeclQName = (javax.xml.namespace.QName) rootDecl;
1508                 fRootElementDeclaration = null;
1509             }
1510             else {
1511                 fRootElementDeclaration = (XSElementDecl) rootDecl;
1512                 fRootElementDeclQName = null;
1513             }
1514         }
1515         catch (XMLConfigurationException e) {
1516             fRootElementDeclQName = null;
1517             fRootElementDeclaration = null;
1518         }
1519 
1520         boolean ignoreXSIType = componentManager.getFeature(IGNORE_XSI_TYPE, false);
1521 
1522         // An initial value of -1 means that the root element considers itself
1523         // below the depth where xsi:type stopped being ignored (which means that
1524         // xsi:type attributes will not be ignored for the entire document)
1525         fIgnoreXSITypeDepth = ignoreXSIType ? 0 : -1;
1526 
1527         try {
1528             fIDCChecking = componentManager.getFeature(IDENTITY_CONSTRAINT_CHECKING);
1529         }
1530         catch (XMLConfigurationException e) {
1531             fIDCChecking = true;
1532         }
1533 
1534         try {
1535             fValidationState.setIdIdrefChecking(componentManager.getFeature(ID_IDREF_CHECKING));
1536         }
1537         catch (XMLConfigurationException e) {
1538             fValidationState.setIdIdrefChecking(true);
1539         }
1540 
1541         try {
1542             fValidationState.setUnparsedEntityChecking(componentManager.getFeature(UNPARSED_ENTITY_CHECKING));
1543         }
1544         catch (XMLConfigurationException e) {
1545             fValidationState.setUnparsedEntityChecking(true);
1546         }
1547 
1548         // get schema location properties
1549         try {
1550             fExternalSchemas = (String) componentManager.getProperty(SCHEMA_LOCATION);
1551             fExternalNoNamespaceSchema =
1552                 (String) componentManager.getProperty(SCHEMA_NONS_LOCATION);
1553         } catch (XMLConfigurationException e) {
1554             fExternalSchemas = null;
1555             fExternalNoNamespaceSchema = null;
1556         }
1557 
1558         // store the external schema locations. they are set when reset is called,
1559         // so any other schemaLocation declaration for the same namespace will be
1560         // effectively ignored. becuase we choose to take first location hint
1561         // available for a particular namespace.
1562         XMLSchemaLoader.processExternalHints(
1563             fExternalSchemas,
1564             fExternalNoNamespaceSchema,
1565             fLocationPairs,
1566             fXSIErrorReporter.fErrorReporter);
1567 
1568         fJaxpSchemaSource = componentManager.getProperty(JAXP_SCHEMA_SOURCE, null);
1569 
1570         // clear grammars, and put the one for schema namespace there
1571         fGrammarPool = (XMLGrammarPool) componentManager.getProperty(XMLGRAMMAR_POOL, null);
1572 
1573         fState4XsiType.setSymbolTable(symbolTable);
1574         fState4ApplyDefault.setSymbolTable(symbolTable);
1575 
1576     } // reset(XMLComponentManager)
1577 
1578     //
1579     // FieldActivator methods
1580     //
1581 
1582     /**
1583      * Start the value scope for the specified identity constraint. This
1584      * method is called when the selector matches in order to initialize
1585      * the value store.
1586      *
1587      * @param identityConstraint The identity constraint.
1588      */
1589     public void startValueScopeFor(IdentityConstraint identityConstraint, int initialDepth) {
1590 
1591         ValueStoreBase valueStore =
1592             fValueStoreCache.getValueStoreFor(identityConstraint, initialDepth);
1593         valueStore.startValueScope();
1594 
1595     } // startValueScopeFor(IdentityConstraint identityConstraint)
1596 
1597     /**
1598      * Request to activate the specified field. This method returns the
1599      * matcher for the field.
1600      *
1601      * @param field The field to activate.
1602      */
1603     public XPathMatcher activateField(Field field, int initialDepth) {
1604         ValueStore valueStore =
1605             fValueStoreCache.getValueStoreFor(field.getIdentityConstraint(), initialDepth);
1606         XPathMatcher matcher = field.createMatcher(valueStore);
1607         fMatcherStack.addMatcher(matcher);
1608         matcher.startDocumentFragment();
1609         return matcher;
1610     } // activateField(Field):XPathMatcher
1611 
1612     /**
1613      * Ends the value scope for the specified identity constraint.
1614      *
1615      * @param identityConstraint The identity constraint.
1616      */
1617     public void endValueScopeFor(IdentityConstraint identityConstraint, int initialDepth) {
1618 
1619         ValueStoreBase valueStore =
1620             fValueStoreCache.getValueStoreFor(identityConstraint, initialDepth);
1621         valueStore.endValueScope();
1622 
1623     } // endValueScopeFor(IdentityConstraint)
1624 
1625     // a utility method for Identity constraints
1626     private void activateSelectorFor(IdentityConstraint ic) {
1627         Selector selector = ic.getSelector();
1628         FieldActivator activator = this;
1629         if (selector == null)
1630             return;
1631         XPathMatcher matcher = selector.createMatcher(activator, fElementDepth);
1632         fMatcherStack.addMatcher(matcher);
1633         matcher.startDocumentFragment();
1634     }
1635 
1636     // Implements XSElementDeclHelper interface
1637     public XSElementDecl getGlobalElementDecl(QName element) {
1638         final SchemaGrammar sGrammar =
1639             findSchemaGrammar(
1640                 XSDDescription.CONTEXT_ELEMENT,
1641                 element.uri,
1642                 null,
1643                 element,
1644                 null);
1645         if (sGrammar != null) {
1646             return sGrammar.getGlobalElementDecl(element.localpart);
1647         }
1648         return null;
1649     }
1650 
1651     //
1652     // Protected methods
1653     //
1654 
1655     /** ensure element stack capacity */
1656     void ensureStackCapacity() {
1657 
1658         if (fElementDepth == fElemDeclStack.length) {
1659             int newSize = fElementDepth + INC_STACK_SIZE;
1660             boolean[] newArrayB = new boolean[newSize];
1661             System.arraycopy(fSubElementStack, 0, newArrayB, 0, fElementDepth);
1662             fSubElementStack = newArrayB;
1663 
1664             XSElementDecl[] newArrayE = new XSElementDecl[newSize];
1665             System.arraycopy(fElemDeclStack, 0, newArrayE, 0, fElementDepth);
1666             fElemDeclStack = newArrayE;
1667 
1668             newArrayB = new boolean[newSize];
1669             System.arraycopy(fNilStack, 0, newArrayB, 0, fElementDepth);
1670             fNilStack = newArrayB;
1671 
1672             XSNotationDecl[] newArrayN = new XSNotationDecl[newSize];
1673             System.arraycopy(fNotationStack, 0, newArrayN, 0, fElementDepth);
1674             fNotationStack = newArrayN;
1675 
1676             XSTypeDefinition[] newArrayT = new XSTypeDefinition[newSize];
1677             System.arraycopy(fTypeStack, 0, newArrayT, 0, fElementDepth);
1678             fTypeStack = newArrayT;
1679 
1680             XSCMValidator[] newArrayC = new XSCMValidator[newSize];
1681             System.arraycopy(fCMStack, 0, newArrayC, 0, fElementDepth);
1682             fCMStack = newArrayC;
1683 
1684             newArrayB = new boolean[newSize];
1685             System.arraycopy(fSawTextStack, 0, newArrayB, 0, fElementDepth);
1686             fSawTextStack = newArrayB;
1687 
1688             newArrayB = new boolean[newSize];
1689             System.arraycopy(fStringContent, 0, newArrayB, 0, fElementDepth);
1690             fStringContent = newArrayB;
1691 
1692             newArrayB = new boolean[newSize];
1693             System.arraycopy(fStrictAssessStack, 0, newArrayB, 0, fElementDepth);
1694             fStrictAssessStack = newArrayB;
1695 
1696             int[][] newArrayIA = new int[newSize][];
1697             System.arraycopy(fCMStateStack, 0, newArrayIA, 0, fElementDepth);
1698             fCMStateStack = newArrayIA;
1699         }
1700 
1701     } // ensureStackCapacity
1702 
1703     // handle start document
1704     void handleStartDocument(XMLLocator locator, String encoding) {
1705         if (fIDCChecking) {
1706             fValueStoreCache.startDocument();
1707         }
1708         if (fAugPSVI) {
1709             fCurrentPSVI.fGrammars = null;
1710             fCurrentPSVI.fSchemaInformation = null;
1711         }
1712     } // handleStartDocument(XMLLocator,String)
1713 
1714     void handleEndDocument() {
1715         if (fIDCChecking) {
1716             fValueStoreCache.endDocument();
1717         }
1718     } // handleEndDocument()
1719 
1720     // handle character contents
1721     // returns the normalized string if possible, otherwise the original string
1722     XMLString handleCharacters(XMLString text) {
1723 
1724         if (fSkipValidationDepth >= 0)
1725             return text;
1726 
1727         fSawText = fSawText || text.length > 0;
1728 
1729         // Note: data in EntityRef and CDATA is normalized as well
1730         // if whitespace == -1 skip normalization, because it is a complexType
1731         // or a union type.
1732         if (fNormalizeData && fWhiteSpace != -1 && fWhiteSpace != XSSimpleType.WS_PRESERVE) {
1733             // normalize data
1734             normalizeWhitespace(text, fWhiteSpace == XSSimpleType.WS_COLLAPSE);
1735             text = fNormalizedStr;
1736         }
1737         if (fAppendBuffer)
1738             fBuffer.append(text.ch, text.offset, text.length);
1739 
1740         // When it's a complex type with element-only content, we need to
1741         // find out whether the content contains any non-whitespace character.
1742         fSawOnlyWhitespaceInElementContent = false;
1743         if (fCurrentType != null
1744             && fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
1745             XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType;
1746             if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT) {
1747                 // data outside of element content
1748                 for (int i = text.offset; i < text.offset + text.length; i++) {
1749                     if (!XMLChar.isSpace(text.ch[i])) {
1750                         fSawCharacters = true;
1751                         break;
1752                     }
1753                     fSawOnlyWhitespaceInElementContent = !fSawCharacters;
1754                 }
1755             }
1756         }
1757 
1758         return text;
1759     } // handleCharacters(XMLString)
1760 
1761     /**
1762      * Normalize whitespace in an XMLString according to the rules defined
1763      * in XML Schema specifications.
1764      * @param value    The string to normalize.
1765      * @param collapse replace or collapse
1766      */
1767     private void normalizeWhitespace(XMLString value, boolean collapse) {
1768         boolean skipSpace = collapse;
1769         boolean sawNonWS = false;
1770         boolean leading = false;
1771         boolean trailing = false;
1772         char c;
1773         int size = value.offset + value.length;
1774 
1775         // ensure the ch array is big enough
1776         if (fNormalizedStr.ch == null || fNormalizedStr.ch.length < value.length + 1) {
1777             fNormalizedStr.ch = new char[value.length + 1];
1778         }
1779         // don't include the leading ' ' for now. might include it later.
1780         fNormalizedStr.offset = 1;
1781         fNormalizedStr.length = 1;
1782 
1783         for (int i = value.offset; i < size; i++) {
1784             c = value.ch[i];
1785             if (XMLChar.isSpace(c)) {
1786                 if (!skipSpace) {
1787                     // take the first whitespace as a space and skip the others
1788                     fNormalizedStr.ch[fNormalizedStr.length++] = ' ';
1789                     skipSpace = collapse;
1790                 }
1791                 if (!sawNonWS) {
1792                     // this is a leading whitespace, record it
1793                     leading = true;
1794                 }
1795             } else {
1796                 fNormalizedStr.ch[fNormalizedStr.length++] = c;
1797                 skipSpace = false;
1798                 sawNonWS = true;
1799             }
1800         }
1801         if (skipSpace) {
1802             if (fNormalizedStr.length > 1) {
1803                 // if we finished on a space trim it but also record it
1804                 fNormalizedStr.length--;
1805                 trailing = true;
1806             } else if (leading && !fFirstChunk) {
1807                 // if all we had was whitespace we skipped record it as
1808                 // trailing whitespace as well
1809                 trailing = true;
1810             }
1811         }
1812 
1813         if (fNormalizedStr.length > 1) {
1814             if (!fFirstChunk && (fWhiteSpace == XSSimpleType.WS_COLLAPSE)) {
1815                 if (fTrailing) {
1816                     // previous chunk ended on whitespace
1817                     // insert whitespace
1818                     fNormalizedStr.offset = 0;
1819                     fNormalizedStr.ch[0] = ' ';
1820                 } else if (leading) {
1821                     // previous chunk ended on character,
1822                     // this chunk starts with whitespace
1823                     fNormalizedStr.offset = 0;
1824                     fNormalizedStr.ch[0] = ' ';
1825                 }
1826             }
1827         }
1828 
1829         // The length includes the leading ' '. Now removing it.
1830         fNormalizedStr.length -= fNormalizedStr.offset;
1831 
1832         fTrailing = trailing;
1833 
1834         if (trailing || sawNonWS)
1835             fFirstChunk = false;
1836     }
1837 
1838     private void normalizeWhitespace(String value, boolean collapse) {
1839         boolean skipSpace = collapse;
1840         char c;
1841         int size = value.length();
1842 
1843         // ensure the ch array is big enough
1844         if (fNormalizedStr.ch == null || fNormalizedStr.ch.length < size) {
1845             fNormalizedStr.ch = new char[size];
1846         }
1847         fNormalizedStr.offset = 0;
1848         fNormalizedStr.length = 0;
1849 
1850         for (int i = 0; i < size; i++) {
1851             c = value.charAt(i);
1852             if (XMLChar.isSpace(c)) {
1853                 if (!skipSpace) {
1854                     // take the first whitespace as a space and skip the others
1855                     fNormalizedStr.ch[fNormalizedStr.length++] = ' ';
1856                     skipSpace = collapse;
1857                 }
1858             } else {
1859                 fNormalizedStr.ch[fNormalizedStr.length++] = c;
1860                 skipSpace = false;
1861             }
1862         }
1863         if (skipSpace) {
1864             if (fNormalizedStr.length != 0)
1865                 // if we finished on a space trim it but also record it
1866                 fNormalizedStr.length--;
1867         }
1868     }
1869 
1870     // handle ignorable whitespace
1871     void handleIgnorableWhitespace(XMLString text) {
1872 
1873         if (fSkipValidationDepth >= 0)
1874             return;
1875 
1876         // REVISIT: the same process needs to be performed as handleCharacters.
1877         // only it's simpler here: we know all characters are whitespaces.
1878 
1879     } // handleIgnorableWhitespace(XMLString)
1880 
1881     /** Handle element. */
1882     Augmentations handleStartElement(QName element, XMLAttributes attributes, Augmentations augs) {
1883 
1884         if (DEBUG) {
1885             System.out.println("==>handleStartElement: " + element);
1886         }
1887 
1888         // root element
1889         if (fElementDepth == -1 && fValidationManager.isGrammarFound()) {
1890             if (fSchemaType == null) {
1891                 // schemaType is not specified
1892                 // if a DTD grammar is found, we do the same thing as Dynamic:
1893                 // if a schema grammar is found, validation is performed;
1894                 // otherwise, skip the whole document.
1895                 fSchemaDynamicValidation = true;
1896             } else {
1897                 // [1] Either schemaType is DTD, and in this case validate/schema is turned off
1898                 // [2] Validating against XML Schemas only
1899                 //   [a] dynamic validation is false: report error if SchemaGrammar is not found
1900                 //   [b] dynamic validation is true: if grammar is not found ignore.
1901             }
1902 
1903         }
1904 
1905         // get xsi:schemaLocation and xsi:noNamespaceSchemaLocation attributes,
1906         // parse them to get the grammars. But only do this if the grammar can grow.
1907         if (!fUseGrammarPoolOnly) {
1908             String sLocation =
1909                 attributes.getValue(SchemaSymbols.URI_XSI, SchemaSymbols.XSI_SCHEMALOCATION);
1910             String nsLocation =
1911                 attributes.getValue(SchemaSymbols.URI_XSI, SchemaSymbols.XSI_NONAMESPACESCHEMALOCATION);
1912             //store the location hints..  we need to do it so that we can defer the loading of grammar until
1913             //there is a reference to a component from that namespace. To provide location hints to the
1914             //application for a namespace
1915             storeLocations(sLocation, nsLocation);
1916         }
1917 
1918         // if we are in the content of "skip", then just skip this element
1919         // REVISIT:  is this the correct behaviour for ID constraints?  -NG
1920         if (fSkipValidationDepth >= 0) {
1921             fElementDepth++;
1922             if (fAugPSVI)
1923                 augs = getEmptyAugs(augs);
1924             return augs;
1925         }
1926 
1927         // if we are not skipping this element, and there is a content model,
1928         // we try to find the corresponding decl object for this element.
1929         // the reason we move this part of code here is to make sure the
1930         // error reported here (if any) is stored within the parent element's
1931         // context, instead of that of the current element.
1932         Object decl = null;
1933         if (fCurrentCM != null) {
1934             decl = fCurrentCM.oneTransition(element, fCurrCMState, fSubGroupHandler);
1935             // it could be an element decl or a wildcard decl
1936             if (fCurrCMState[0] == XSCMValidator.FIRST_ERROR) {
1937                 XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType;
1938                 //REVISIT: is it the only case we will have particle = null?
1939                 List<Object> next;
1940                 if (ctype.fParticle != null
1941                     && (next = fCurrentCM.whatCanGoHere(fCurrCMState)).size() > 0) {
1942                     String expected = expectedStr(next);
1943                     final int[] occurenceInfo = fCurrentCM.occurenceInfo(fCurrCMState);
1944                     String elemExpandedQname = (element.uri != null) ? "{"+'"'+element.uri+'"'+":"+element.localpart+"}" : element.localpart;
1945                     if (occurenceInfo != null) {
1946                         final int minOccurs = occurenceInfo[0];
1947                         final int maxOccurs = occurenceInfo[1];
1948                         final int count = occurenceInfo[2];
1949                         // Check if this is a violation of minOccurs
1950                         if (count < minOccurs) {
1951                             final int required = minOccurs - count;
1952                             if (required > 1) {
1953                                 reportSchemaError("cvc-complex-type.2.4.h", new Object[] { element.rawname,
1954                                         fCurrentCM.getTermName(occurenceInfo[3]), Integer.toString(minOccurs), Integer.toString(required) });
1955                             }
1956                             else {
1957                                 reportSchemaError("cvc-complex-type.2.4.g", new Object[] { element.rawname,
1958                                         fCurrentCM.getTermName(occurenceInfo[3]), Integer.toString(minOccurs) });
1959                             }
1960                         }
1961                         // Check if this is a violation of maxOccurs
1962                         else if (count >= maxOccurs && maxOccurs != SchemaSymbols.OCCURRENCE_UNBOUNDED) {
1963                             reportSchemaError("cvc-complex-type.2.4.e", new Object[] { element.rawname,
1964                                     expected, Integer.toString(maxOccurs) });
1965                         }
1966                         else {
1967                             reportSchemaError("cvc-complex-type.2.4.a", new Object[] { elemExpandedQname, expected });
1968                         }
1969                     }
1970                     else {
1971                         reportSchemaError("cvc-complex-type.2.4.a", new Object[] { elemExpandedQname, expected });
1972                     }
1973                 }
1974                 else {
1975                     final int[] occurenceInfo = fCurrentCM.occurenceInfo(fCurrCMState);
1976                     if (occurenceInfo != null) {
1977                         final int maxOccurs = occurenceInfo[1];
1978                         final int count = occurenceInfo[2];
1979                         // Check if this is a violation of maxOccurs
1980                         if (count >= maxOccurs && maxOccurs != SchemaSymbols.OCCURRENCE_UNBOUNDED) {
1981                             reportSchemaError("cvc-complex-type.2.4.f", new Object[] { fCurrentCM.getTermName(occurenceInfo[3]), Integer.toString(maxOccurs) });
1982                         }
1983                         else {
1984                             reportSchemaError("cvc-complex-type.2.4.d", new Object[] { element.rawname });
1985                         }
1986                     }
1987                     else {
1988                         reportSchemaError("cvc-complex-type.2.4.d", new Object[] { element.rawname });
1989                     }
1990                 }
1991             }
1992         }
1993 
1994         // if it's not the root element, we push the current states in the stacks
1995         if (fElementDepth != -1) {
1996             ensureStackCapacity();
1997             fSubElementStack[fElementDepth] = true;
1998             fSubElement = false;
1999             fElemDeclStack[fElementDepth] = fCurrentElemDecl;
2000             fNilStack[fElementDepth] = fNil;
2001             fNotationStack[fElementDepth] = fNotation;
2002             fTypeStack[fElementDepth] = fCurrentType;
2003             fStrictAssessStack[fElementDepth] = fStrictAssess;
2004             fCMStack[fElementDepth] = fCurrentCM;
2005             fCMStateStack[fElementDepth] = fCurrCMState;
2006             fSawTextStack[fElementDepth] = fSawText;
2007             fStringContent[fElementDepth] = fSawCharacters;
2008         }
2009 
2010         // increase the element depth after we've saved
2011         // all states for the parent element
2012         fElementDepth++;
2013         fCurrentElemDecl = null;
2014         XSWildcardDecl wildcard = null;
2015         fCurrentType = null;
2016         fStrictAssess = true;
2017         fNil = false;
2018         fNotation = null;
2019 
2020         // and the buffer to hold the value of the element
2021         fBuffer.setLength(0);
2022         fSawText = false;
2023         fSawCharacters = false;
2024 
2025         // check what kind of declaration the "decl" from
2026         // oneTransition() maps to
2027         if (decl != null) {
2028             if (decl instanceof XSElementDecl) {
2029                 fCurrentElemDecl = (XSElementDecl) decl;
2030             } else {
2031                 wildcard = (XSWildcardDecl) decl;
2032             }
2033         }
2034 
2035         // if the wildcard is skip, then return
2036         if (wildcard != null && wildcard.fProcessContents == XSWildcardDecl.PC_SKIP) {
2037             fSkipValidationDepth = fElementDepth;
2038             if (fAugPSVI)
2039                 augs = getEmptyAugs(augs);
2040             return augs;
2041         }
2042 
2043         if (fElementDepth == 0) {
2044             // 1.1.1.1 An element declaration was stipulated by the processor
2045             if (fRootElementDeclaration != null) {
2046                 fCurrentElemDecl = fRootElementDeclaration;
2047                 checkElementMatchesRootElementDecl(fCurrentElemDecl, element);
2048             }
2049             else if (fRootElementDeclQName != null) {
2050                 processRootElementDeclQName(fRootElementDeclQName, element);
2051             }
2052             // 1.2.1.1 A type definition was stipulated by the processor
2053             else if (fRootTypeDefinition != null) {
2054                 fCurrentType = fRootTypeDefinition;
2055             }
2056             else if (fRootTypeQName != null) {
2057                 processRootTypeQName(fRootTypeQName);
2058             }
2059         }
2060 
2061         // if there was no processor stipulated type
2062         if (fCurrentType == null) {
2063             // try again to get the element decl:
2064             // case 1: find declaration for root element
2065             // case 2: find declaration for element from another namespace
2066             if (fCurrentElemDecl == null) {
2067                 // try to find schema grammar by different means..
2068                 SchemaGrammar sGrammar =
2069                     findSchemaGrammar(
2070                         XSDDescription.CONTEXT_ELEMENT,
2071                         element.uri,
2072                         null,
2073                         element,
2074                         attributes);
2075                 if (sGrammar != null) {
2076                     fCurrentElemDecl = sGrammar.getGlobalElementDecl(element.localpart);
2077                 }
2078             }
2079 
2080             if (fCurrentElemDecl != null) {
2081                 // then get the type
2082                 fCurrentType = fCurrentElemDecl.fType;
2083             }
2084         }
2085 
2086         // check if we should be ignoring xsi:type on this element
2087         if (fElementDepth == fIgnoreXSITypeDepth && fCurrentElemDecl == null) {
2088             fIgnoreXSITypeDepth++;
2089         }
2090 
2091         // process xsi:type attribute information
2092         String xsiType = null;
2093         if (fElementDepth >= fIgnoreXSITypeDepth) {
2094             xsiType = attributes.getValue(SchemaSymbols.URI_XSI, SchemaSymbols.XSI_TYPE);
2095         }
2096 
2097         // if no decl/type found for the current element
2098         if (fCurrentType == null && xsiType == null) {
2099             // if this is the validation root, report an error, because
2100             // we can't find eith decl or type for this element
2101             // REVISIT: should we report error, or warning?
2102             if (fElementDepth == 0) {
2103                 // for dynamic validation, skip the whole content,
2104                 // because no grammar was found.
2105                 if (fDynamicValidation || fSchemaDynamicValidation) {
2106                     // no schema grammar was found, but it's either dynamic
2107                     // validation, or another kind of grammar was found (DTD,
2108                     // for example). The intended behavior here is to skip
2109                     // the whole document. To improve performance, we try to
2110                     // remove the validator from the pipeline, since it's not
2111                     // supposed to do anything.
2112                     if (fDocumentSource != null) {
2113                         fDocumentSource.setDocumentHandler(fDocumentHandler);
2114                         if (fDocumentHandler != null)
2115                             fDocumentHandler.setDocumentSource(fDocumentSource);
2116                         // indicate that the validator was removed.
2117                         fElementDepth = -2;
2118                         return augs;
2119                     }
2120 
2121                     fSkipValidationDepth = fElementDepth;
2122                     if (fAugPSVI)
2123                         augs = getEmptyAugs(augs);
2124                     return augs;
2125                 }
2126                 // We don't call reportSchemaError here, because the spec
2127                 // doesn't think it's invalid not to be able to find a
2128                 // declaration or type definition for an element. Xerces is
2129                 // reporting it as an error for historical reasons, but in
2130                 // PSVI, we shouldn't mark this element as invalid because
2131                 // of this. - SG
2132                 fXSIErrorReporter.fErrorReporter.reportError(
2133                     XSMessageFormatter.SCHEMA_DOMAIN,
2134                     "cvc-elt.1.a",
2135                     new Object[] { element.rawname },
2136                     XMLErrorReporter.SEVERITY_ERROR);
2137             }
2138             // if wildcard = strict, report error.
2139             // needs to be called before fXSIErrorReporter.pushContext()
2140             // so that the error belongs to the parent element.
2141             else if (wildcard != null && wildcard.fProcessContents == XSWildcardDecl.PC_STRICT) {
2142                 // report error, because wilcard = strict
2143                 reportSchemaError("cvc-complex-type.2.4.c", new Object[] { element.rawname });
2144             }
2145             // no element decl or type found for this element.
2146             // Allowed by the spec, we can choose to either laxly assess this
2147             // element, or to skip it. Now we choose lax assessment.
2148             fCurrentType = SchemaGrammar.fAnyType;
2149             fStrictAssess = false;
2150             fNFullValidationDepth = fElementDepth;
2151             // any type has mixed content, so we don't need to append buffer
2152             fAppendBuffer = false;
2153 
2154             // push error reporter context: record the current position
2155             // This has to happen after we process skip contents,
2156             // otherwise push and pop won't be correctly paired.
2157             fXSIErrorReporter.pushContext();
2158         } else {
2159             // push error reporter context: record the current position
2160             // This has to happen after we process skip contents,
2161             // otherwise push and pop won't be correctly paired.
2162             fXSIErrorReporter.pushContext();
2163 
2164             // get xsi:type
2165             if (xsiType != null) {
2166                 XSTypeDefinition oldType = fCurrentType;
2167                 fCurrentType = getAndCheckXsiType(element, xsiType, attributes);
2168                 // If it fails, use the old type. Use anyType if ther is no old type.
2169                 if (fCurrentType == null) {
2170                     if (oldType == null)
2171                         fCurrentType = SchemaGrammar.fAnyType;
2172                     else
2173                         fCurrentType = oldType;
2174                 }
2175             }
2176 
2177             fNNoneValidationDepth = fElementDepth;
2178             // if the element has a fixed value constraint, we need to append
2179             if (fCurrentElemDecl != null
2180                 && fCurrentElemDecl.getConstraintType() == XSConstants.VC_FIXED) {
2181                 fAppendBuffer = true;
2182             }
2183             // if the type is simple, we need to append
2184             else if (fCurrentType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
2185                 fAppendBuffer = true;
2186             } else {
2187                 // if the type is simple content complex type, we need to append
2188                 XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType;
2189                 fAppendBuffer = (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE);
2190             }
2191         }
2192 
2193         // Element Locally Valid (Element)
2194         // 2 Its {abstract} must be false.
2195         if (fCurrentElemDecl != null && fCurrentElemDecl.getAbstract())
2196             reportSchemaError("cvc-elt.2", new Object[] { element.rawname });
2197 
2198         // make the current element validation root
2199         if (fElementDepth == 0) {
2200             fValidationRoot = element.rawname;
2201         }
2202 
2203         // update normalization flags
2204         if (fNormalizeData) {
2205             // reset values
2206             fFirstChunk = true;
2207             fTrailing = false;
2208             fUnionType = false;
2209             fWhiteSpace = -1;
2210         }
2211 
2212         // Element Locally Valid (Type)
2213         // 2 Its {abstract} must be false.
2214         if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
2215             XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType;
2216             if (ctype.getAbstract()) {
2217                 reportSchemaError("cvc-type.2", new Object[] { element.rawname });
2218             }
2219             if (fNormalizeData) {
2220                 // find out if the content type is simple and if variety is union
2221                 // to be able to do character normalization
2222                 if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) {
2223                     if (ctype.fXSSimpleType.getVariety() == XSSimpleType.VARIETY_UNION) {
2224                         fUnionType = true;
2225                     } else {
2226                         try {
2227                             fWhiteSpace = ctype.fXSSimpleType.getWhitespace();
2228                         } catch (DatatypeException e) {
2229                             // do nothing
2230                         }
2231                     }
2232                 }
2233             }
2234         }
2235         // normalization: simple type
2236         else if (fNormalizeData) {
2237             // if !union type
2238             XSSimpleType dv = (XSSimpleType) fCurrentType;
2239             if (dv.getVariety() == XSSimpleType.VARIETY_UNION) {
2240                 fUnionType = true;
2241             } else {
2242                 try {
2243                     fWhiteSpace = dv.getWhitespace();
2244                 } catch (DatatypeException e) {
2245                     // do nothing
2246                 }
2247             }
2248         }
2249 
2250         // then try to get the content model
2251         fCurrentCM = null;
2252         if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
2253             fCurrentCM = ((XSComplexTypeDecl) fCurrentType).getContentModel(fCMBuilder);
2254         }
2255 
2256         // and get the initial content model state
2257         fCurrCMState = null;
2258         if (fCurrentCM != null)
2259             fCurrCMState = fCurrentCM.startContentModel();
2260 
2261         // get information about xsi:nil
2262         String xsiNil = attributes.getValue(SchemaSymbols.URI_XSI, SchemaSymbols.XSI_NIL);
2263         // only deal with xsi:nil when there is an element declaration
2264         if (xsiNil != null && fCurrentElemDecl != null)
2265             fNil = getXsiNil(element, xsiNil);
2266 
2267         // now validate everything related with the attributes
2268         // first, get the attribute group
2269         XSAttributeGroupDecl attrGrp = null;
2270         if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
2271             XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType;
2272             attrGrp = ctype.getAttrGrp();
2273         }
2274 
2275         if (fIDCChecking) {
2276             // activate identity constraints
2277             fValueStoreCache.startElement();
2278             fMatcherStack.pushContext();
2279             //if (fCurrentElemDecl != null && fCurrentElemDecl.fIDCPos > 0 && !fIgnoreIDC) {
2280             if (fCurrentElemDecl != null && fCurrentElemDecl.fIDCPos > 0) {
2281                 fIdConstraint = true;
2282                 // initialize when identity constrains are defined for the elem
2283                 fValueStoreCache.initValueStoresFor(fCurrentElemDecl, this);
2284             }
2285         }
2286         processAttributes(element, attributes, attrGrp);
2287 
2288         // add default attributes
2289         if (attrGrp != null) {
2290             addDefaultAttributes(element, attributes, attrGrp);
2291         }
2292 
2293         // call all active identity constraints
2294         int count = fMatcherStack.getMatcherCount();
2295         for (int i = 0; i < count; i++) {
2296             XPathMatcher matcher = fMatcherStack.getMatcherAt(i);
2297             matcher.startElement( element, attributes);
2298         }
2299 
2300         if (fAugPSVI) {
2301             augs = getEmptyAugs(augs);
2302 
2303             // PSVI: add validation context
2304             fCurrentPSVI.fValidationContext = fValidationRoot;
2305             // PSVI: add element declaration
2306             fCurrentPSVI.fDeclaration = fCurrentElemDecl;
2307             // PSVI: add element type
2308             fCurrentPSVI.fTypeDecl = fCurrentType;
2309             // PSVI: add notation attribute
2310             fCurrentPSVI.fNotation = fNotation;
2311             // PSVI: add nil
2312             fCurrentPSVI.fNil = fNil;
2313         }
2314 
2315         return augs;
2316 
2317     } // handleStartElement(QName,XMLAttributes,boolean)
2318 
2319     /**
2320      *  Handle end element. If there is not text content, and there is a
2321      *  {value constraint} on the corresponding element decl, then
2322      * set the fDefaultValue XMLString representing the default value.
2323      */
2324     Augmentations handleEndElement(QName element, Augmentations augs) {
2325 
2326         if (DEBUG) {
2327             System.out.println("==>handleEndElement:" + element);
2328         }
2329         // if we are skipping, return
2330         if (fSkipValidationDepth >= 0) {
2331             // but if this is the top element that we are skipping,
2332             // restore the states.
2333             if (fSkipValidationDepth == fElementDepth && fSkipValidationDepth > 0) {
2334                 // set the partial validation depth to the depth of parent
2335                 fNFullValidationDepth = fSkipValidationDepth - 1;
2336                 fSkipValidationDepth = -1;
2337                 fElementDepth--;
2338                 fSubElement = fSubElementStack[fElementDepth];
2339                 fCurrentElemDecl = fElemDeclStack[fElementDepth];
2340                 fNil = fNilStack[fElementDepth];
2341                 fNotation = fNotationStack[fElementDepth];
2342                 fCurrentType = fTypeStack[fElementDepth];
2343                 fCurrentCM = fCMStack[fElementDepth];
2344                 fStrictAssess = fStrictAssessStack[fElementDepth];
2345                 fCurrCMState = fCMStateStack[fElementDepth];
2346                 fSawText = fSawTextStack[fElementDepth];
2347                 fSawCharacters = fStringContent[fElementDepth];
2348             }
2349             else {
2350                 fElementDepth--;
2351             }
2352 
2353             // PSVI: validation attempted:
2354             // use default values in psvi item for
2355             // validation attempted, validity, and error codes
2356 
2357             // check extra schema constraints on root element
2358             if (fElementDepth == -1 && fFullChecking && !fUseGrammarPoolOnly) {
2359                 XSConstraints.fullSchemaChecking(
2360                     fGrammarBucket,
2361                     fSubGroupHandler,
2362                     fCMBuilder,
2363                     fXSIErrorReporter.fErrorReporter);
2364             }
2365 
2366             if (fAugPSVI)
2367                 augs = getEmptyAugs(augs);
2368             return augs;
2369         }
2370 
2371         // now validate the content of the element
2372         processElementContent(element);
2373 
2374         if (fIDCChecking) {
2375             // Element Locally Valid (Element)
2376             // 6 The element information item must be valid with respect to each of the {identity-constraint definitions} as per Identity-constraint Satisfied (3.11.4).
2377 
2378             // call matchers and de-activate context
2379             int oldCount = fMatcherStack.getMatcherCount();
2380             for (int i = oldCount - 1; i >= 0; i--) {
2381                 XPathMatcher matcher = fMatcherStack.getMatcherAt(i);
2382                 if (fCurrentElemDecl == null) {
2383                     matcher.endElement(element, fCurrentType, false, fValidatedInfo.actualValue, fValidatedInfo.actualValueType, fValidatedInfo.itemValueTypes);
2384                 }
2385                 else {
2386                     matcher.endElement(
2387                             element,
2388                             fCurrentType,
2389                             fCurrentElemDecl.getNillable(),
2390                             fDefaultValue == null
2391                                 ? fValidatedInfo.actualValue
2392                                 : fCurrentElemDecl.fDefault.actualValue,
2393                             fDefaultValue == null
2394                                 ? fValidatedInfo.actualValueType
2395                                 : fCurrentElemDecl.fDefault.actualValueType,
2396                             fDefaultValue == null
2397                                 ? fValidatedInfo.itemValueTypes
2398                                 : fCurrentElemDecl.fDefault.itemValueTypes);
2399                 }
2400             }
2401 
2402             if (fMatcherStack.size() > 0) {
2403                 fMatcherStack.popContext();
2404             }
2405 
2406             int newCount = fMatcherStack.getMatcherCount();
2407             // handle everything *but* keyref's.
2408             for (int i = oldCount - 1; i >= newCount; i--) {
2409                 XPathMatcher matcher = fMatcherStack.getMatcherAt(i);
2410                 if (matcher instanceof Selector.Matcher) {
2411                     Selector.Matcher selMatcher = (Selector.Matcher) matcher;
2412                     IdentityConstraint id;
2413                     if ((id = selMatcher.getIdentityConstraint()) != null
2414                             && id.getCategory() != IdentityConstraint.IC_KEYREF) {
2415                         fValueStoreCache.transplant(id, selMatcher.getInitialDepth());
2416                     }
2417                 }
2418             }
2419 
2420             // now handle keyref's/...
2421             for (int i = oldCount - 1; i >= newCount; i--) {
2422                 XPathMatcher matcher = fMatcherStack.getMatcherAt(i);
2423                 if (matcher instanceof Selector.Matcher) {
2424                     Selector.Matcher selMatcher = (Selector.Matcher) matcher;
2425                     IdentityConstraint id;
2426                     if ((id = selMatcher.getIdentityConstraint()) != null
2427                             && id.getCategory() == IdentityConstraint.IC_KEYREF) {
2428                         ValueStoreBase values =
2429                             fValueStoreCache.getValueStoreFor(id, selMatcher.getInitialDepth());
2430                         // nothing to do if nothing matched, or if not all
2431                         // fields are present.
2432                         if (values != null && values.fValuesCount == values.fFieldCount)
2433                             values.endDocumentFragment();
2434                     }
2435                 }
2436             }
2437             fValueStoreCache.endElement();
2438         }
2439 
2440         // Check if we should modify the xsi:type ignore depth
2441         // This check is independent of whether this is the validation root,
2442         // and should be done before the element depth is decremented.
2443         if (fElementDepth < fIgnoreXSITypeDepth) {
2444             fIgnoreXSITypeDepth--;
2445         }
2446 
2447         SchemaGrammar[] grammars = null;
2448         // have we reached the end tag of the validation root?
2449         if (fElementDepth == 0) {
2450             // 7 If the element information item is the validation root, it must be valid per Validation Root Valid (ID/IDREF) (3.3.4).
2451             Iterator<String> invIdRefs = fValidationState.checkIDRefID();
2452             fValidationState.resetIDTables();
2453             if (invIdRefs != null) {
2454                 while (invIdRefs.hasNext()) {
2455                     reportSchemaError("cvc-id.1", new Object[] { invIdRefs.next() });
2456                 }
2457             }
2458             // check extra schema constraints
2459             if (fFullChecking && !fUseGrammarPoolOnly) {
2460                 XSConstraints.fullSchemaChecking(
2461                     fGrammarBucket,
2462                     fSubGroupHandler,
2463                     fCMBuilder,
2464                     fXSIErrorReporter.fErrorReporter);
2465             }
2466 
2467             grammars = fGrammarBucket.getGrammars();
2468             // return the final set of grammars validator ended up with
2469             if (fGrammarPool != null) {
2470                 // Set grammars as immutable
2471                 for (int k=0; k < grammars.length; k++) {
2472                     grammars[k].setImmutable(true);
2473                 }
2474                 fGrammarPool.cacheGrammars(XMLGrammarDescription.XML_SCHEMA, grammars);
2475             }
2476             augs = endElementPSVI(true, grammars, augs);
2477         } else {
2478             augs = endElementPSVI(false, grammars, augs);
2479 
2480             // decrease element depth and restore states
2481             fElementDepth--;
2482 
2483             // get the states for the parent element.
2484             fSubElement = fSubElementStack[fElementDepth];
2485             fCurrentElemDecl = fElemDeclStack[fElementDepth];
2486             fNil = fNilStack[fElementDepth];
2487             fNotation = fNotationStack[fElementDepth];
2488             fCurrentType = fTypeStack[fElementDepth];
2489             fCurrentCM = fCMStack[fElementDepth];
2490             fStrictAssess = fStrictAssessStack[fElementDepth];
2491             fCurrCMState = fCMStateStack[fElementDepth];
2492             fSawText = fSawTextStack[fElementDepth];
2493             fSawCharacters = fStringContent[fElementDepth];
2494 
2495             // We should have a stack for whitespace value, and pop it up here.
2496             // But when fWhiteSpace != -1, and we see a sub-element, it must be
2497             // an error (at least for Schema 1.0). So for valid documents, the
2498             // only value we are going to push/pop in the stack is -1.
2499             // Here we just mimic the effect of popping -1. -SG
2500             fWhiteSpace = -1;
2501             // Same for append buffer. Simple types and elements with fixed
2502             // value constraint don't allow sub-elements. -SG
2503             fAppendBuffer = false;
2504             // same here.
2505             fUnionType = false;
2506         }
2507 
2508         return augs;
2509     } // handleEndElement(QName,boolean)*/
2510 
2511     final Augmentations endElementPSVI(
2512         boolean root,
2513         SchemaGrammar[] grammars,
2514         Augmentations augs) {
2515 
2516         if (fAugPSVI) {
2517             augs = getEmptyAugs(augs);
2518 
2519             // the 5 properties sent on startElement calls
2520             fCurrentPSVI.fDeclaration = this.fCurrentElemDecl;
2521             fCurrentPSVI.fTypeDecl = this.fCurrentType;
2522             fCurrentPSVI.fNotation = this.fNotation;
2523             fCurrentPSVI.fValidationContext = this.fValidationRoot;
2524             fCurrentPSVI.fNil = this.fNil;
2525             // PSVI: validation attempted
2526             // nothing below or at the same level has none or partial
2527             // (which means this level is strictly assessed, and all chidren
2528             // are full), so this one has full
2529             if (fElementDepth > fNFullValidationDepth) {
2530                 fCurrentPSVI.fValidationAttempted = ElementPSVI.VALIDATION_FULL;
2531             }
2532             // nothing below or at the same level has full or partial
2533             // (which means this level is not strictly assessed, and all chidren
2534             // are none), so this one has none
2535             else if (fElementDepth > fNNoneValidationDepth) {
2536                 fCurrentPSVI.fValidationAttempted = ElementPSVI.VALIDATION_NONE;
2537             }
2538             // otherwise partial, and anything above this level will be partial
2539             else {
2540                 fCurrentPSVI.fValidationAttempted = ElementPSVI.VALIDATION_PARTIAL;
2541             }
2542 
2543             // this guarantees that depth settings do not cross-over between sibling nodes
2544             if (fNFullValidationDepth == fElementDepth) {
2545                 fNFullValidationDepth = fElementDepth - 1;
2546             }
2547             if (fNNoneValidationDepth == fElementDepth) {
2548                 fNNoneValidationDepth = fElementDepth - 1;
2549             }
2550 
2551             if (fDefaultValue != null)
2552                 fCurrentPSVI.fSpecified = true;
2553             fCurrentPSVI.fValue.copyFrom(fValidatedInfo);
2554 
2555             if (fStrictAssess) {
2556                 // get all errors for the current element, its attribute,
2557                 // and subelements (if they were strictly assessed).
2558                 // any error would make this element invalid.
2559                 // and we merge these errors to the parent element.
2560                 String[] errors = fXSIErrorReporter.mergeContext();
2561 
2562                 // PSVI: error codes
2563                 fCurrentPSVI.fErrors = errors;
2564                 // PSVI: validity
2565                 fCurrentPSVI.fValidity =
2566                     (errors == null) ? ElementPSVI.VALIDITY_VALID : ElementPSVI.VALIDITY_INVALID;
2567             } else {
2568                 // PSVI: validity
2569                 fCurrentPSVI.fValidity = ElementPSVI.VALIDITY_NOTKNOWN;
2570                 // Discard the current context: ignore any error happened within
2571                 // the sub-elements/attributes of this element, because those
2572                 // errors won't affect the validity of the parent elements.
2573                 fXSIErrorReporter.popContext();
2574             }
2575 
2576             if (root) {
2577                 // store [schema information] in the PSVI
2578                 fCurrentPSVI.fGrammars = grammars;
2579                 fCurrentPSVI.fSchemaInformation = null;
2580             }
2581         }
2582 
2583         return augs;
2584 
2585     }
2586 
2587     Augmentations getEmptyAugs(Augmentations augs) {
2588         if (augs == null) {
2589             augs = fAugmentations;
2590             augs.removeAllItems();
2591         }
2592         augs.putItem(Constants.ELEMENT_PSVI, fCurrentPSVI);
2593         fCurrentPSVI.reset();
2594 
2595         return augs;
2596     }
2597 
2598     void storeLocations(String sLocation, String nsLocation) {
2599         if (sLocation != null) {
2600             if (!XMLSchemaLoader.tokenizeSchemaLocationStr(sLocation,
2601                     fLocationPairs, fLocator == null ? null : fLocator.getExpandedSystemId())) {
2602                 // error!
2603                 fXSIErrorReporter.reportError(
2604                     XSMessageFormatter.SCHEMA_DOMAIN,
2605                     "SchemaLocation",
2606                     new Object[] { sLocation },
2607                     XMLErrorReporter.SEVERITY_WARNING);
2608             }
2609         }
2610         if (nsLocation != null) {
2611             XMLSchemaLoader.LocationArray la = fLocationPairs.get(XMLSymbols.EMPTY_STRING);
2612             if (la == null) {
2613                 la = new XMLSchemaLoader.LocationArray();
2614                 fLocationPairs.put(XMLSymbols.EMPTY_STRING, la);
2615             }
2616             if (fLocator != null) {
2617                 try {
2618                     nsLocation = XMLEntityManager.expandSystemId(nsLocation, fLocator.getExpandedSystemId(), false);
2619                 } catch (MalformedURIException e) {
2620                 }
2621             }
2622             la.addLocation(nsLocation);
2623         }
2624 
2625     } //storeLocations
2626 
2627     //this is the function where logic of retrieving grammar is written , parser first tries to get the grammar from
2628     //the local pool, if not in local pool, it gives chance to application to be able to retrieve the grammar, then it
2629     //tries to parse the grammar using location hints from the give namespace.
2630     SchemaGrammar findSchemaGrammar(
2631         short contextType,
2632         String namespace,
2633         QName enclosingElement,
2634         QName triggeringComponent,
2635         XMLAttributes attributes) {
2636         SchemaGrammar grammar = null;
2637         //get the grammar from local pool...
2638         grammar = fGrammarBucket.getGrammar(namespace);
2639 
2640         if (grammar == null) {
2641             fXSDDescription.setNamespace(namespace);
2642             // give a chance to application to be able to retreive the grammar.
2643             if (fGrammarPool != null) {
2644                 grammar = (SchemaGrammar) fGrammarPool.retrieveGrammar(fXSDDescription);
2645                 if (grammar != null) {
2646                     // put this grammar into the bucket, along with grammars
2647                     // imported by it (directly or indirectly)
2648                     if (!fGrammarBucket.putGrammar(grammar, true, fNamespaceGrowth)) {
2649                         // REVISIT: a conflict between new grammar(s) and grammars
2650                         // in the bucket. What to do? A warning? An exception?
2651                         fXSIErrorReporter.fErrorReporter.reportError(
2652                             XSMessageFormatter.SCHEMA_DOMAIN,
2653                             "GrammarConflict",
2654                             null,
2655                             XMLErrorReporter.SEVERITY_WARNING);
2656                         grammar = null;
2657                     }
2658                 }
2659             }
2660         }
2661 
2662         if (!fUseGrammarPoolOnly && (grammar == null ||
2663             (fNamespaceGrowth && !hasSchemaComponent(grammar, contextType, triggeringComponent)))) {
2664             fXSDDescription.reset();
2665             fXSDDescription.fContextType = contextType;
2666             fXSDDescription.setNamespace(namespace);
2667             fXSDDescription.fEnclosedElementName = enclosingElement;
2668             fXSDDescription.fTriggeringComponent = triggeringComponent;
2669             fXSDDescription.fAttributes = attributes;
2670             if (fLocator != null) {
2671                 fXSDDescription.setBaseSystemId(fLocator.getExpandedSystemId());
2672             }
2673 
2674             Map<String, XMLSchemaLoader.LocationArray> locationPairs = fLocationPairs;
2675             XMLSchemaLoader.LocationArray locationArray =
2676                 locationPairs.get(namespace == null ? XMLSymbols.EMPTY_STRING : namespace);
2677             if (locationArray != null) {
2678                 String[] temp = locationArray.getLocationArray();
2679                 if (temp.length != 0) {
2680                     setLocationHints(fXSDDescription, temp, grammar);
2681                 }
2682             }
2683 
2684             if (grammar == null || fXSDDescription.fLocationHints != null) {
2685                 boolean toParseSchema = true;
2686                 if (grammar != null) {
2687                      // use location hints instead
2688                     locationPairs = Collections.emptyMap();
2689                 }
2690 
2691                 // try to parse the grammar using location hints from that namespace..
2692                 try {
2693                     XMLInputSource xis =
2694                         XMLSchemaLoader.resolveDocument(
2695                             fXSDDescription,
2696                             locationPairs,
2697                             fEntityResolver);
2698                     if (grammar != null && fNamespaceGrowth) {
2699                         try {
2700                             // if we are dealing with a different schema location, then include the new schema
2701                             // into the existing grammar
2702                             if (grammar.getDocumentLocations().contains(XMLEntityManager.expandSystemId(xis.getSystemId(), xis.getBaseSystemId(), false))) {
2703                                 toParseSchema = false;
2704                             }
2705                         }
2706                         catch (MalformedURIException e) {
2707                         }
2708                     }
2709                     if (toParseSchema) {
2710                         grammar = fSchemaLoader.loadSchema(fXSDDescription, xis, fLocationPairs);
2711                     }
2712                 }
2713                 catch (IOException ex) {
2714                     final String [] locationHints = fXSDDescription.getLocationHints();
2715                     fXSIErrorReporter.fErrorReporter.reportError(
2716                         XSMessageFormatter.SCHEMA_DOMAIN,
2717                         "schema_reference.4",
2718                         new Object[] { locationHints != null ? locationHints[0] : XMLSymbols.EMPTY_STRING },
2719                         XMLErrorReporter.SEVERITY_WARNING, ex);
2720                 }
2721             }
2722         }
2723 
2724         return grammar;
2725 
2726     } //findSchemaGrammar
2727 
2728     private boolean hasSchemaComponent(SchemaGrammar grammar, short contextType, QName triggeringComponent) {
2729         if (grammar != null && triggeringComponent != null) {
2730             String localName = triggeringComponent.localpart;
2731             if (localName != null && localName.length() > 0) {
2732                 switch (contextType) {
2733                     case XSDDescription.CONTEXT_ELEMENT:
2734                         return grammar.getElementDeclaration(localName) != null;
2735                     case XSDDescription.CONTEXT_ATTRIBUTE:
2736                         return grammar.getAttributeDeclaration(localName) != null;
2737                     case XSDDescription.CONTEXT_XSITYPE:
2738                         return grammar.getTypeDefinition(localName) != null;
2739                 }
2740             }
2741         }
2742         return false;
2743     }
2744 
2745     private void setLocationHints(XSDDescription desc, String[] locations, SchemaGrammar grammar) {
2746         int length = locations.length;
2747         if (grammar == null) {
2748             fXSDDescription.fLocationHints = new String[length];
2749             System.arraycopy(locations, 0, fXSDDescription.fLocationHints, 0, length);
2750         }
2751         else {
2752             setLocationHints(desc, locations, grammar.getDocumentLocations());
2753         }
2754     }
2755 
2756     private void setLocationHints(XSDDescription desc, String[] locations, StringList docLocations) {
2757         int length = locations.length;
2758         String[] hints = new String[length];
2759         int counter = 0;
2760 
2761         for (int i=0; i<length; i++) {
2762             if (!docLocations.contains(locations[i])) {
2763                 hints[counter++] = locations[i];
2764             }
2765         }
2766 
2767         if (counter > 0) {
2768             if (counter == length) {
2769                 fXSDDescription.fLocationHints = hints;
2770             }
2771             else {
2772                 fXSDDescription.fLocationHints = new String[counter];
2773                 System.arraycopy(hints, 0, fXSDDescription.fLocationHints, 0, counter);
2774             }
2775         }
2776     }
2777 
2778     XSTypeDefinition getAndCheckXsiType(QName element, String xsiType, XMLAttributes attributes) {
2779         // This method also deals with clause 1.2.1.2 of the constraint
2780         // Validation Rule: Schema-Validity Assessment (Element)
2781 
2782         // Element Locally Valid (Element)
2783         // 4 If there is an attribute information item among the element information item's [attributes] whose [namespace name] is identical to http://www.w3.org/2001/XMLSchema-instance and whose [local name] is type, then all of the following must be true:
2784         // 4.1 The normalized value of that attribute information item must be valid with respect to the built-in QName simple type, as defined by String Valid (3.14.4);
2785         QName typeName = null;
2786         try {
2787             typeName = (QName) fQNameDV.validate(xsiType, fValidationState, null);
2788         } catch (InvalidDatatypeValueException e) {
2789             reportSchemaError(e.getKey(), e.getArgs());
2790             reportSchemaError(
2791                 "cvc-elt.4.1",
2792                 new Object[] {
2793                     element.rawname,
2794                     SchemaSymbols.URI_XSI + "," + SchemaSymbols.XSI_TYPE,
2795                     xsiType });
2796             return null;
2797         }
2798 
2799         // 4.2 The local name and namespace name (as defined in QName Interpretation (3.15.3)), of the actual value of that attribute information item must resolve to a type definition, as defined in QName resolution (Instance) (3.15.4)
2800         XSTypeDefinition type = null;
2801         // if the namespace is schema namespace, first try built-in types
2802         if (typeName.uri == SchemaSymbols.URI_SCHEMAFORSCHEMA) {
2803             type = SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(typeName.localpart);
2804         }
2805         // if it's not schema built-in types, then try to get a grammar
2806         if (type == null) {
2807             //try to find schema grammar by different means....
2808             SchemaGrammar grammar =
2809                 findSchemaGrammar(
2810                     XSDDescription.CONTEXT_XSITYPE,
2811                     typeName.uri,
2812                     element,
2813                     typeName,
2814                     attributes);
2815 
2816             if (grammar != null)
2817                 type = grammar.getGlobalTypeDecl(typeName.localpart);
2818         }
2819         // still couldn't find the type, report an error
2820         if (type == null) {
2821             reportSchemaError("cvc-elt.4.2", new Object[] { element.rawname, xsiType });
2822             return null;
2823         }
2824 
2825         // if there is no current type, set this one as current.
2826         // and we don't need to do extra checking
2827         if (fCurrentType != null) {
2828             short block = XSConstants.DERIVATION_NONE;
2829             // 4.3 The local type definition must be validly derived from the {type definition} given the union of the {disallowed substitutions} and the {type definition}'s {prohibited substitutions}, as defined in Type Derivation OK (Complex) (3.4.6) (if it is a complex type definition), or given {disallowed substitutions} as defined in Type Derivation OK (Simple) (3.14.6) (if it is a simple type definition).
2830             // Note: It's possible to have fCurrentType be non-null and fCurrentElemDecl
2831             // be null, if the current type is set using the property "root-type-definition".
2832             // In that case, we don't disallow any substitutions. -PM
2833             if (fCurrentElemDecl != null) {
2834                 block = fCurrentElemDecl.fBlock;
2835             }
2836             if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
2837                 block |= ((XSComplexTypeDecl) fCurrentType).fBlock;
2838             }
2839             if (!XSConstraints.checkTypeDerivationOk(type, fCurrentType, block)) {
2840                 reportSchemaError(
2841                         "cvc-elt.4.3",
2842                         new Object[] { element.rawname, xsiType, XS10TypeHelper.getSchemaTypeName(fCurrentType)});
2843             }
2844         }
2845 
2846         return type;
2847     } //getAndCheckXsiType
2848 
2849     boolean getXsiNil(QName element, String xsiNil) {
2850         // Element Locally Valid (Element)
2851         // 3 The appropriate case among the following must be true:
2852         // 3.1 If {nillable} is false, then there must be no attribute information item among the element information item's [attributes] whose [namespace name] is identical to http://www.w3.org/2001/XMLSchema-instance and whose [local name] is nil.
2853         if (fCurrentElemDecl != null && !fCurrentElemDecl.getNillable()) {
2854             reportSchemaError(
2855                 "cvc-elt.3.1",
2856                 new Object[] {
2857                     element.rawname,
2858                     SchemaSymbols.URI_XSI + "," + SchemaSymbols.XSI_NIL });
2859         }
2860         // 3.2 If {nillable} is true and there is such an attribute information item and its actual value is true , then all of the following must be true:
2861         // 3.2.2 There must be no fixed {value constraint}.
2862         else {
2863             String value = XMLChar.trim(xsiNil);
2864             if (value.equals(SchemaSymbols.ATTVAL_TRUE)
2865                 || value.equals(SchemaSymbols.ATTVAL_TRUE_1)) {
2866                 if (fCurrentElemDecl != null
2867                     && fCurrentElemDecl.getConstraintType() == XSConstants.VC_FIXED) {
2868                     reportSchemaError(
2869                         "cvc-elt.3.2.2",
2870                         new Object[] {
2871                             element.rawname,
2872                             SchemaSymbols.URI_XSI + "," + SchemaSymbols.XSI_NIL });
2873                 }
2874                 return true;
2875             }
2876         }
2877         return false;
2878     }
2879 
2880     void processAttributes(QName element, XMLAttributes attributes, XSAttributeGroupDecl attrGrp) {
2881 
2882         if (DEBUG) {
2883             System.out.println("==>processAttributes: " + attributes.getLength());
2884         }
2885 
2886         // whether we have seen a Wildcard ID.
2887         String wildcardIDName = null;
2888 
2889         // for each present attribute
2890         int attCount = attributes.getLength();
2891 
2892         Augmentations augs = null;
2893         AttributePSVImpl attrPSVI = null;
2894 
2895         boolean isSimple =
2896             fCurrentType == null || fCurrentType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE;
2897 
2898         XSObjectList attrUses = null;
2899         int useCount = 0;
2900         XSWildcardDecl attrWildcard = null;
2901         if (!isSimple) {
2902             attrUses = attrGrp.getAttributeUses();
2903             useCount = attrUses.getLength();
2904             attrWildcard = attrGrp.fAttributeWC;
2905         }
2906 
2907         // Element Locally Valid (Complex Type)
2908         // 3 For each attribute information item in the element information item's [attributes] excepting those whose [namespace name] is identical to http://www.w3.org/2001/XMLSchema-instance and whose [local name] is one of type, nil, schemaLocation or noNamespaceSchemaLocation, the appropriate case among the following must be true:
2909         // get the corresponding attribute decl
2910         for (int index = 0; index < attCount; index++) {
2911 
2912             attributes.getName(index, fTempQName);
2913 
2914             if (DEBUG) {
2915                 System.out.println("==>process attribute: " + fTempQName);
2916             }
2917 
2918             if (fAugPSVI || fIdConstraint) {
2919                 augs = attributes.getAugmentations(index);
2920                 attrPSVI = (AttributePSVImpl) augs.getItem(Constants.ATTRIBUTE_PSVI);
2921                 if (attrPSVI != null) {
2922                     attrPSVI.reset();
2923                 } else {
2924                     attrPSVI = new AttributePSVImpl();
2925                     augs.putItem(Constants.ATTRIBUTE_PSVI, attrPSVI);
2926                 }
2927                 // PSVI attribute: validation context
2928                 attrPSVI.fValidationContext = fValidationRoot;
2929             }
2930 
2931             // Element Locally Valid (Type)
2932             // 3.1.1 The element information item's [attributes] must be empty, excepting those
2933             // whose [namespace name] is identical to http://www.w3.org/2001/XMLSchema-instance and
2934             // whose [local name] is one of type, nil, schemaLocation or noNamespaceSchemaLocation.
2935 
2936             // for the 4 xsi attributes, get appropriate decl, and validate
2937             if (fTempQName.uri == SchemaSymbols.URI_XSI) {
2938                 XSAttributeDecl attrDecl = null;
2939                 if (fTempQName.localpart == SchemaSymbols.XSI_TYPE) {
2940                     attrDecl = XSI_TYPE;
2941                 }
2942                 else if (fTempQName.localpart == SchemaSymbols.XSI_NIL) {
2943                     attrDecl = XSI_NIL;
2944                 }
2945                 else if (fTempQName.localpart == SchemaSymbols.XSI_SCHEMALOCATION) {
2946                     attrDecl = XSI_SCHEMALOCATION;
2947                 }
2948                 else if (fTempQName.localpart == SchemaSymbols.XSI_NONAMESPACESCHEMALOCATION) {
2949                     attrDecl = XSI_NONAMESPACESCHEMALOCATION;
2950                 }
2951                 if (attrDecl != null) {
2952                     processOneAttribute(element, attributes, index, attrDecl, null, attrPSVI);
2953                     continue;
2954                 }
2955             }
2956 
2957             // for namespace attributes, no_validation/unknow_validity
2958             if (fTempQName.rawname == XMLSymbols.PREFIX_XMLNS
2959                 || fTempQName.rawname.startsWith("xmlns:")) {
2960                 continue;
2961             }
2962 
2963             // simple type doesn't allow any other attributes
2964             if (isSimple) {
2965                 reportSchemaError(
2966                     "cvc-type.3.1.1",
2967                     new Object[] { element.rawname, fTempQName.rawname });
2968                 continue;
2969             }
2970 
2971             // it's not xmlns, and not xsi, then we need to find a decl for it
2972             XSAttributeUseImpl currUse = null, oneUse;
2973             for (int i = 0; i < useCount; i++) {
2974                 oneUse = (XSAttributeUseImpl) attrUses.item(i);
2975                 if (oneUse.fAttrDecl.fName == fTempQName.localpart
2976                     && oneUse.fAttrDecl.fTargetNamespace == fTempQName.uri) {
2977                     currUse = oneUse;
2978                     break;
2979                 }
2980             }
2981 
2982             // 3.2 otherwise all of the following must be true:
2983             // 3.2.1 There must be an {attribute wildcard}.
2984             // 3.2.2 The attribute information item must be valid with respect to it as defined in Item Valid (Wildcard) (3.10.4).
2985 
2986             // if failed, get it from wildcard
2987             if (currUse == null) {
2988                 //if (attrWildcard == null)
2989                 //    reportSchemaError("cvc-complex-type.3.2.1", new Object[]{element.rawname, fTempQName.rawname});
2990                 if (attrWildcard == null || !attrWildcard.allowNamespace(fTempQName.uri)) {
2991                     // so this attribute is not allowed
2992                     reportSchemaError(
2993                         "cvc-complex-type.3.2.2",
2994                         new Object[] { element.rawname, fTempQName.rawname });
2995 
2996                     // We have seen an attribute that was not declared
2997                     fNFullValidationDepth = fElementDepth;
2998 
2999                     continue;
3000                 }
3001             }
3002 
3003             XSAttributeDecl currDecl = null;
3004             if (currUse != null) {
3005                 currDecl = currUse.fAttrDecl;
3006             } else {
3007                 // which means it matches a wildcard
3008                 // skip it if processContents is skip
3009                 if (attrWildcard.fProcessContents == XSWildcardDecl.PC_SKIP)
3010                     continue;
3011 
3012                 //try to find grammar by different means...
3013                 SchemaGrammar grammar =
3014                     findSchemaGrammar(
3015                         XSDDescription.CONTEXT_ATTRIBUTE,
3016                         fTempQName.uri,
3017                         element,
3018                         fTempQName,
3019                         attributes);
3020 
3021                 if (grammar != null) {
3022                     currDecl = grammar.getGlobalAttributeDecl(fTempQName.localpart);
3023                 }
3024 
3025                 // if can't find
3026                 if (currDecl == null) {
3027                     // if strict, report error
3028                     if (attrWildcard.fProcessContents == XSWildcardDecl.PC_STRICT) {
3029                         reportSchemaError(
3030                             "cvc-complex-type.3.2.2",
3031                             new Object[] { element.rawname, fTempQName.rawname });
3032                     }
3033 
3034                     // then continue to the next attribute
3035                     continue;
3036                 } else {
3037                     // 5 Let [Definition:]  the wild IDs be the set of all attribute information item to which clause 3.2 applied and whose validation resulted in a context-determined declaration of mustFind or no context-determined declaration at all, and whose [local name] and [namespace name] resolve (as defined by QName resolution (Instance) (3.15.4)) to an attribute declaration whose {type definition} is or is derived from ID. Then all of the following must be true:
3038                     // 5.1 There must be no more than one item in wild IDs.
3039                     if (currDecl.fType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE
3040                         && (currDecl.fType).isIDType()) {
3041                         if (wildcardIDName != null) {
3042                             reportSchemaError(
3043                                 "cvc-complex-type.5.1",
3044                                 new Object[] { element.rawname, currDecl.fName, wildcardIDName });
3045                         } else
3046                             wildcardIDName = currDecl.fName;
3047                     }
3048                 }
3049             }
3050 
3051             processOneAttribute(element, attributes, index, currDecl, currUse, attrPSVI);
3052         } // end of for (all attributes)
3053 
3054         // 5.2 If wild IDs is non-empty, there must not be any attribute uses among the {attribute uses} whose {attribute declaration}'s {type definition} is or is derived from ID.
3055         if (!isSimple && attrGrp.fIDAttrName != null && wildcardIDName != null) {
3056             reportSchemaError(
3057                 "cvc-complex-type.5.2",
3058                 new Object[] { element.rawname, wildcardIDName, attrGrp.fIDAttrName });
3059         }
3060 
3061     } //processAttributes
3062 
3063     void processOneAttribute(
3064         QName element,
3065         XMLAttributes attributes,
3066         int index,
3067         XSAttributeDecl currDecl,
3068         XSAttributeUseImpl currUse,
3069         AttributePSVImpl attrPSVI) {
3070 
3071         String attrValue = attributes.getValue(index);
3072         fXSIErrorReporter.pushContext();
3073 
3074         // Attribute Locally Valid
3075         // For an attribute information item to be locally valid with respect to an attribute declaration all of the following must be true:
3076         // 1 The declaration must not be absent (see Missing Sub-components (5.3) for how this can fail to be the case).
3077         // 2 Its {type definition} must not be absent.
3078         // 3 The item's normalized value must be locally valid with respect to that {type definition} as per String Valid (3.14.4).
3079         // get simple type
3080         XSSimpleType attDV = currDecl.fType;
3081 
3082         Object actualValue = null;
3083         try {
3084             actualValue = attDV.validate(attrValue, fValidationState, fValidatedInfo);
3085             // store the normalized value
3086             if (fNormalizeData) {
3087                 attributes.setValue(index, fValidatedInfo.normalizedValue);
3088             }
3089             // PSVI: element notation
3090             if (attDV.getVariety() == XSSimpleType.VARIETY_ATOMIC
3091                 && attDV.getPrimitiveKind() == XSSimpleType.PRIMITIVE_NOTATION) {
3092                 QName qName = (QName) actualValue;
3093                 SchemaGrammar grammar = fGrammarBucket.getGrammar(qName.uri);
3094 
3095                 //REVISIT: is it possible for the notation to be in different namespace than the attribute
3096                 //with which it is associated, CHECK !!  <fof n1:att1 = "n2:notation1" ..>
3097                 // should we give chance to the application to be able to  retrieve a grammar - nb
3098                 //REVISIT: what would be the triggering component here.. if it is attribute value that
3099                 // triggered the loading of grammar ?? -nb
3100 
3101                 if (grammar != null) {
3102                     fNotation = grammar.getGlobalNotationDecl(qName.localpart);
3103                 }
3104             }
3105         }
3106         catch (InvalidDatatypeValueException idve) {
3107             reportSchemaError(idve.getKey(), idve.getArgs());
3108             reportSchemaError(
3109                 "cvc-attribute.3",
3110                 new Object[] { element.rawname, fTempQName.rawname, attrValue,
3111                         (attDV instanceof XSSimpleTypeDecl) ?
3112                                 ((XSSimpleTypeDecl) attDV).getTypeName() : attDV.getName()});
3113         }
3114 
3115         // get the value constraint from use or decl
3116         // 4 The item's actual value must match the value of the {value constraint}, if it is present and fixed.                 // now check the value against the simpleType
3117         if (actualValue != null && currDecl.getConstraintType() == XSConstants.VC_FIXED) {
3118             if (!ValidatedInfo.isComparable(fValidatedInfo, currDecl.fDefault) || !actualValue.equals(currDecl.fDefault.actualValue)) {
3119                 reportSchemaError(
3120                     "cvc-attribute.4",
3121                     new Object[] {
3122                         element.rawname,
3123                         fTempQName.rawname,
3124                         attrValue,
3125                         currDecl.fDefault.stringValue()});
3126             }
3127         }
3128 
3129         // 3.1 If there is among the {attribute uses} an attribute use with an {attribute declaration} whose {name} matches the attribute information item's [local name] and whose {target namespace} is identical to the attribute information item's [namespace name] (where an absent {target namespace} is taken to be identical to a [namespace name] with no value), then the attribute information must be valid with respect to that attribute use as per Attribute Locally Valid (Use) (3.5.4). In this case the {attribute declaration} of that attribute use is the context-determined declaration for the attribute information item with respect to Schema-Validity Assessment (Attribute) (3.2.4) and Assessment Outcome (Attribute) (3.2.5).
3130         if (actualValue != null
3131             && currUse != null
3132             && currUse.fConstraintType == XSConstants.VC_FIXED) {
3133             if (!ValidatedInfo.isComparable(fValidatedInfo, currUse.fDefault) || !actualValue.equals(currUse.fDefault.actualValue)) {
3134                 reportSchemaError(
3135                     "cvc-complex-type.3.1",
3136                     new Object[] {
3137                         element.rawname,
3138                         fTempQName.rawname,
3139                         attrValue,
3140                         currUse.fDefault.stringValue()});
3141             }
3142         }
3143         if (fIdConstraint) {
3144             attrPSVI.fValue.copyFrom(fValidatedInfo);
3145         }
3146 
3147         if (fAugPSVI) {
3148             // PSVI: attribute declaration
3149             attrPSVI.fDeclaration = currDecl;
3150             // PSVI: attribute type
3151             attrPSVI.fTypeDecl = attDV;
3152 
3153             // PSVI: attribute normalized value
3154             // NOTE: we always store the normalized value, even if it's invlid,
3155             // because it might still be useful to the user. But when the it's
3156             // not valid, the normalized value is not trustable.
3157             attrPSVI.fValue.copyFrom(fValidatedInfo);
3158 
3159             // PSVI: validation attempted:
3160             attrPSVI.fValidationAttempted = AttributePSVI.VALIDATION_FULL;
3161 
3162             // We have seen an attribute that was declared.
3163             if (!fUseGrammarPoolOnly &&
3164                     !(fElementDepth < fIgnoreXSITypeDepth && fCurrentElemDecl == null)) {
3165                 //only when USE_GRAMMAR_POOL_ONLY and IGNORE_XSI_TYPE are not set
3166                 fNNoneValidationDepth = fElementDepth;
3167             }
3168 
3169             String[] errors = fXSIErrorReporter.mergeContext();
3170             // PSVI: error codes
3171             attrPSVI.fErrors = errors;
3172             // PSVI: validity
3173             attrPSVI.fValidity =
3174                 (errors == null) ? AttributePSVI.VALIDITY_VALID : AttributePSVI.VALIDITY_INVALID;
3175         }
3176     }
3177 
3178     void addDefaultAttributes(
3179         QName element,
3180         XMLAttributes attributes,
3181         XSAttributeGroupDecl attrGrp) {
3182         // Check after all specified attrs are scanned
3183         // (1) report error for REQUIRED attrs that are missing (V_TAGc)
3184         // REVISIT: should we check prohibited attributes?
3185         // (2) report error for PROHIBITED attrs that are present (V_TAGc)
3186         // (3) add default attrs (FIXED and NOT_FIXED)
3187         //
3188         if (DEBUG) {
3189             System.out.println("==>addDefaultAttributes: " + element);
3190         }
3191         XSObjectList attrUses = attrGrp.getAttributeUses();
3192         int useCount = attrUses.getLength();
3193         XSAttributeUseImpl currUse;
3194         XSAttributeDecl currDecl;
3195         short constType;
3196         ValidatedInfo defaultValue;
3197         boolean isSpecified;
3198         QName attName;
3199         // for each attribute use
3200         for (int i = 0; i < useCount; i++) {
3201 
3202             currUse = (XSAttributeUseImpl) attrUses.item(i);
3203             currDecl = currUse.fAttrDecl;
3204             // get value constraint
3205             constType = currUse.fConstraintType;
3206             defaultValue = currUse.fDefault;
3207             if (constType == XSConstants.VC_NONE) {
3208                 constType = currDecl.getConstraintType();
3209                 defaultValue = currDecl.fDefault;
3210             }
3211             // whether this attribute is specified
3212             isSpecified = attributes.getValue(currDecl.fTargetNamespace, currDecl.fName) != null;
3213 
3214             // Element Locally Valid (Complex Type)
3215             // 4 The {attribute declaration} of each attribute use in the {attribute uses} whose
3216             // {required} is true matches one of the attribute information items in the element
3217             // information item's [attributes] as per clause 3.1 above.
3218             if (currUse.fUse == SchemaSymbols.USE_REQUIRED) {
3219                 if (!isSpecified)
3220                     reportSchemaError(
3221                         "cvc-complex-type.4",
3222                         new Object[] { element.rawname, currDecl.fName });
3223             }
3224             // if the attribute is not specified, then apply the value constraint
3225             if (!isSpecified && constType != XSConstants.VC_NONE) {
3226                 attName =
3227                     new QName(null, currDecl.fName, currDecl.fName, currDecl.fTargetNamespace);
3228                 String normalized = (defaultValue != null) ? defaultValue.stringValue() : "";
3229                 int attrIndex;
3230                 if (attributes instanceof XMLAttributesImpl) {
3231                     XMLAttributesImpl attrs = (XMLAttributesImpl) attributes;
3232                     attrIndex = attrs.getLength();
3233                     attrs.addAttributeNS(attName, "CDATA", normalized);
3234                 }
3235                 else {
3236                     attrIndex = attributes.addAttribute(attName, "CDATA", normalized);
3237                 }
3238 
3239                 if (fAugPSVI) {
3240 
3241                     // PSVI: attribute is "schema" specified
3242                     Augmentations augs = attributes.getAugmentations(attrIndex);
3243                     AttributePSVImpl attrPSVI = new AttributePSVImpl();
3244                     augs.putItem(Constants.ATTRIBUTE_PSVI, attrPSVI);
3245 
3246                     attrPSVI.fDeclaration = currDecl;
3247                     attrPSVI.fTypeDecl = currDecl.fType;
3248                     attrPSVI.fValue.copyFrom(defaultValue);
3249                     attrPSVI.fValidationContext = fValidationRoot;
3250                     attrPSVI.fValidity = AttributePSVI.VALIDITY_VALID;
3251                     attrPSVI.fValidationAttempted = AttributePSVI.VALIDATION_FULL;
3252                     attrPSVI.fSpecified = true;
3253                 }
3254             }
3255 
3256         } // for
3257     } // addDefaultAttributes
3258 
3259     /**
3260      *  If there is not text content, and there is a
3261      *  {value constraint} on the corresponding element decl, then return
3262      *  an XMLString representing the default value.
3263      */
3264     void processElementContent(QName element) {
3265         // 1 If the item is ?valid? with respect to an element declaration as per Element Locally Valid (Element) (?3.3.4) and the {value constraint} is present, but clause 3.2 of Element Locally Valid (Element) (?3.3.4) above is not satisfied and the item has no element or character information item [children], then schema. Furthermore, the post-schema-validation infoset has the canonical lexical representation of the {value constraint} value as the item's [schema normalized value] property.
3266         if (fCurrentElemDecl != null
3267             && fCurrentElemDecl.fDefault != null
3268             && !fSawText
3269             && !fSubElement
3270             && !fNil) {
3271 
3272             String strv = fCurrentElemDecl.fDefault.stringValue();
3273             int bufLen = strv.length();
3274             if (fNormalizedStr.ch == null || fNormalizedStr.ch.length < bufLen) {
3275                 fNormalizedStr.ch = new char[bufLen];
3276             }
3277             strv.getChars(0, bufLen, fNormalizedStr.ch, 0);
3278             fNormalizedStr.offset = 0;
3279             fNormalizedStr.length = bufLen;
3280             fDefaultValue = fNormalizedStr;
3281         }
3282         // fixed values are handled later, after xsi:type determined.
3283 
3284         fValidatedInfo.normalizedValue = null;
3285 
3286         // Element Locally Valid (Element)
3287         // 3.2.1 The element information item must have no character or element information item [children].
3288         if (fNil) {
3289             if (fSubElement || fSawText) {
3290                 reportSchemaError(
3291                     "cvc-elt.3.2.1",
3292                     new Object[] {
3293                         element.rawname,
3294                         SchemaSymbols.URI_XSI + "," + SchemaSymbols.XSI_NIL });
3295             }
3296         }
3297 
3298         this.fValidatedInfo.reset();
3299 
3300         // 5 The appropriate case among the following must be true:
3301         // 5.1 If the declaration has a {value constraint}, the item has neither element nor character [children] and clause 3.2 has not applied, then all of the following must be true:
3302         if (fCurrentElemDecl != null
3303             && fCurrentElemDecl.getConstraintType() != XSConstants.VC_NONE
3304             && !fSubElement
3305             && !fSawText
3306             && !fNil) {
3307             // 5.1.1 If the actual type definition is a local type definition then the canonical lexical representation of the {value constraint} value must be a valid default for the actual type definition as defined in Element Default Valid (Immediate) (3.3.6).
3308             if (fCurrentType != fCurrentElemDecl.fType) {
3309                 //REVISIT:we should pass ValidatedInfo here.
3310                 if (XSConstraints
3311                     .ElementDefaultValidImmediate(
3312                         fCurrentType,
3313                         fCurrentElemDecl.fDefault.stringValue(),
3314                         fState4XsiType,
3315                         null)
3316                     == null)
3317                     reportSchemaError(
3318                         "cvc-elt.5.1.1",
3319                         new Object[] {
3320                             element.rawname,
3321                             fCurrentType.getName(),
3322                             fCurrentElemDecl.fDefault.stringValue()});
3323             }
3324             // 5.1.2 The element information item with the canonical lexical representation of the {value constraint} value used as its normalized value must be valid with respect to the actual type definition as defined by Element Locally Valid (Type) (3.3.4).
3325             // REVISIT: don't use toString, but validateActualValue instead
3326             //          use the fState4ApplyDefault
3327             elementLocallyValidType(element, fCurrentElemDecl.fDefault.stringValue());
3328         } else {
3329             // The following method call also deal with clause 1.2.2 of the constraint
3330             // Validation Rule: Schema-Validity Assessment (Element)
3331 
3332             // 5.2 If the declaration has no {value constraint} or the item has either element or character [children] or clause 3.2 has applied, then all of the following must be true:
3333             // 5.2.1 The element information item must be valid with respect to the actual type definition as defined by Element Locally Valid (Type) (3.3.4).
3334             Object actualValue = elementLocallyValidType(element, fBuffer);
3335             // 5.2.2 If there is a fixed {value constraint} and clause 3.2 has not applied, all of the following must be true:
3336             if (fCurrentElemDecl != null
3337                 && fCurrentElemDecl.getConstraintType() == XSConstants.VC_FIXED
3338                 && !fNil) {
3339                 String content = fBuffer.toString();
3340                 // 5.2.2.1 The element information item must have no element information item [children].
3341                 if (fSubElement)
3342                     reportSchemaError("cvc-elt.5.2.2.1", new Object[] { element.rawname });
3343                 // 5.2.2.2 The appropriate case among the following must be true:
3344                 if (fCurrentType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
3345                     XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType;
3346                     // 5.2.2.2.1 If the {content type} of the actual type definition is mixed, then the initial value of the item must match the canonical lexical representation of the {value constraint} value.
3347                     if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_MIXED) {
3348                         // REVISIT: how to get the initial value, does whiteSpace count?
3349                         if (!fCurrentElemDecl.fDefault.normalizedValue.equals(content))
3350                             reportSchemaError(
3351                                 "cvc-elt.5.2.2.2.1",
3352                                 new Object[] {
3353                                     element.rawname,
3354                                     content,
3355                                     fCurrentElemDecl.fDefault.normalizedValue });
3356                     }
3357                     // 5.2.2.2.2 If the {content type} of the actual type definition is a simple type definition, then the actual value of the item must match the canonical lexical representation of the {value constraint} value.
3358                     else if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) {
3359                         if (actualValue != null && (!ValidatedInfo.isComparable(fValidatedInfo, fCurrentElemDecl.fDefault)
3360                                 || !actualValue.equals(fCurrentElemDecl.fDefault.actualValue))) {
3361                             reportSchemaError(
3362                                 "cvc-elt.5.2.2.2.2",
3363                                 new Object[] {
3364                                     element.rawname,
3365                                     content,
3366                                     fCurrentElemDecl.fDefault.stringValue()});
3367                         }
3368                     }
3369                 } else if (fCurrentType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
3370                     if (actualValue != null && (!ValidatedInfo.isComparable(fValidatedInfo, fCurrentElemDecl.fDefault)
3371                             || !actualValue.equals(fCurrentElemDecl.fDefault.actualValue))) {
3372                         // REVISIT: the spec didn't mention this case: fixed
3373                         //          value with simple type
3374                         reportSchemaError(
3375                             "cvc-elt.5.2.2.2.2",
3376                             new Object[] {
3377                                 element.rawname,
3378                                 content,
3379                                 fCurrentElemDecl.fDefault.stringValue()});
3380                     }
3381                 }
3382             }
3383         }
3384 
3385         if (fDefaultValue == null && fNormalizeData && fDocumentHandler != null && fUnionType) {
3386             // for union types we need to send data because we delayed sending
3387             // this data when we received it in the characters() call.
3388             String content = fValidatedInfo.normalizedValue;
3389             if (content == null)
3390                 content = fBuffer.toString();
3391 
3392             int bufLen = content.length();
3393             if (fNormalizedStr.ch == null || fNormalizedStr.ch.length < bufLen) {
3394                 fNormalizedStr.ch = new char[bufLen];
3395             }
3396             content.getChars(0, bufLen, fNormalizedStr.ch, 0);
3397             fNormalizedStr.offset = 0;
3398             fNormalizedStr.length = bufLen;
3399             fDocumentHandler.characters(fNormalizedStr, null);
3400         }
3401     } // processElementContent
3402 
3403     Object elementLocallyValidType(QName element, Object textContent) {
3404         if (fCurrentType == null)
3405             return null;
3406 
3407         Object retValue = null;
3408         // Element Locally Valid (Type)
3409         // 3 The appropriate case among the following must be true:
3410         // 3.1 If the type definition is a simple type definition, then all of the following must be true:
3411         if (fCurrentType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
3412             // 3.1.2 The element information item must have no element information item [children].
3413             if (fSubElement)
3414                 reportSchemaError("cvc-type.3.1.2", new Object[] { element.rawname });
3415             // 3.1.3 If clause 3.2 of Element Locally Valid (Element) (3.3.4) did not apply, then the normalized value must be valid with respect to the type definition as defined by String Valid (3.14.4).
3416             if (!fNil) {
3417                 XSSimpleType dv = (XSSimpleType) fCurrentType;
3418                 try {
3419                     if (!fNormalizeData || fUnionType) {
3420                         fValidationState.setNormalizationRequired(true);
3421                     }
3422                     retValue = dv.validate(textContent, fValidationState, fValidatedInfo);
3423                 } catch (InvalidDatatypeValueException e) {
3424                     reportSchemaError(e.getKey(), e.getArgs());
3425                     reportSchemaError(
3426                         "cvc-type.3.1.3",
3427                         new Object[] { element.rawname, textContent });
3428                 }
3429             }
3430         } else {
3431             // 3.2 If the type definition is a complex type definition, then the element information item must be valid with respect to the type definition as per Element Locally Valid (Complex Type) (3.4.4);
3432             retValue = elementLocallyValidComplexType(element, textContent);
3433         }
3434 
3435         return retValue;
3436     } // elementLocallyValidType
3437 
3438     Object elementLocallyValidComplexType(QName element, Object textContent) {
3439         Object actualValue = null;
3440         XSComplexTypeDecl ctype = (XSComplexTypeDecl) fCurrentType;
3441 
3442         // Element Locally Valid (Complex Type)
3443         // For an element information item to be locally valid with respect to a complex type definition all of the following must be true:
3444         // 1 {abstract} is false.
3445         // 2 If clause 3.2 of Element Locally Valid (Element) (3.3.4) did not apply, then the appropriate case among the following must be true:
3446         if (!fNil) {
3447             // 2.1 If the {content type} is empty, then the element information item has no character or element information item [children].
3448             if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_EMPTY
3449                 && (fSubElement || fSawText)) {
3450                 reportSchemaError("cvc-complex-type.2.1", new Object[] { element.rawname });
3451             }
3452             // 2.2 If the {content type} is a simple type definition, then the element information item has no element information item [children], and the normalized value of the element information item is valid with respect to that simple type definition as defined by String Valid (3.14.4).
3453             else if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) {
3454                 if (fSubElement)
3455                     reportSchemaError("cvc-complex-type.2.2", new Object[] { element.rawname });
3456                 XSSimpleType dv = ctype.fXSSimpleType;
3457                 try {
3458                     if (!fNormalizeData || fUnionType) {
3459                         fValidationState.setNormalizationRequired(true);
3460                     }
3461                     actualValue = dv.validate(textContent, fValidationState, fValidatedInfo);
3462                 } catch (InvalidDatatypeValueException e) {
3463                     reportSchemaError(e.getKey(), e.getArgs());
3464                     reportSchemaError("cvc-complex-type.2.2", new Object[] { element.rawname });
3465                 }
3466                 // REVISIT: eventually, this method should return the same actualValue as elementLocallyValidType...
3467                 // obviously it'll return null when the content is complex.
3468             }
3469             // 2.3 If the {content type} is element-only, then the element information item has no character information item [children] other than those whose [character code] is defined as a white space in [XML 1.0 (Second Edition)].
3470             else if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT) {
3471                 if (fSawCharacters) {
3472                     reportSchemaError("cvc-complex-type.2.3", new Object[] { element.rawname });
3473                 }
3474             }
3475             // 2.4 If the {content type} is element-only or mixed, then the sequence of the element information item's element information item [children], if any, taken in order, is valid with respect to the {content type}'s particle, as defined in Element Sequence Locally Valid (Particle) (3.9.4).
3476             if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_ELEMENT
3477                 || ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_MIXED) {
3478                 // if the current state is a valid state, check whether
3479                 // it's one of the final states.
3480                 if (DEBUG) {
3481                     System.out.println(fCurrCMState);
3482                 }
3483                 if (fCurrCMState[0] >= 0 && !fCurrentCM.endContentModel(fCurrCMState)) {
3484                     String expected = expectedStr(fCurrentCM.whatCanGoHere(fCurrCMState));
3485                     final int[] occurenceInfo = fCurrentCM.occurenceInfo(fCurrCMState);
3486                     if (occurenceInfo != null) {
3487                         final int minOccurs = occurenceInfo[0];
3488                         final int count = occurenceInfo[2];
3489                         // Check if this is a violation of minOccurs
3490                         if (count < minOccurs) {
3491                             final int required = minOccurs - count;
3492                             if (required > 1) {
3493                                 reportSchemaError("cvc-complex-type.2.4.j", new Object[] { element.rawname,
3494                                         fCurrentCM.getTermName(occurenceInfo[3]), Integer.toString(minOccurs), Integer.toString(required) });
3495                             }
3496                             else {
3497                                 reportSchemaError("cvc-complex-type.2.4.i", new Object[] { element.rawname,
3498                                         fCurrentCM.getTermName(occurenceInfo[3]), Integer.toString(minOccurs) });
3499                             }
3500                         }
3501                         else {
3502                             reportSchemaError("cvc-complex-type.2.4.b", new Object[] { element.rawname, expected });
3503                         }
3504                     }
3505                     else {
3506                         reportSchemaError("cvc-complex-type.2.4.b", new Object[] { element.rawname, expected });
3507                     }
3508                 } else {
3509                     // Constant space algorithm for a{n,m} for n > 1 and m <= unbounded
3510                     // After the DFA has completed, check minOccurs and maxOccurs
3511                     // for all elements and wildcards in this content model where
3512                     // a{n,m} is subsumed to a* or a+
3513                     List<String> errors = fCurrentCM.checkMinMaxBounds();
3514                     if (errors != null) {
3515                         for (int i = 0; i < errors.size(); i += 2) {
3516                             reportSchemaError(errors.get(i),
3517                                 new Object[] { element.rawname, errors.get(i + 1) });
3518                         }
3519                     }
3520                 }
3521             }
3522         }
3523         return actualValue;
3524     } // elementLocallyValidComplexType
3525 
3526     void processRootTypeQName(final javax.xml.namespace.QName rootTypeQName) {
3527         String rootTypeNamespace = rootTypeQName.getNamespaceURI();
3528         // Add namespace to symbol table, to make sure it's interned.
3529         // This namespace may be later compared with other values using ==.
3530         rootTypeNamespace = fSymbolTable.addSymbol(rootTypeNamespace);
3531         if (rootTypeNamespace != null && rootTypeNamespace.equals(XMLConstants.NULL_NS_URI)) {
3532             rootTypeNamespace = null;
3533         }
3534         if (SchemaSymbols.URI_SCHEMAFORSCHEMA.equals(rootTypeNamespace)) {
3535             fCurrentType = SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(rootTypeQName.getLocalPart());
3536         }
3537         else {
3538             final SchemaGrammar grammarForRootType = findSchemaGrammar(
3539                     XSDDescription.CONTEXT_ELEMENT, rootTypeNamespace, null, null, null);
3540             if (grammarForRootType != null) {
3541                 fCurrentType = grammarForRootType.getGlobalTypeDecl(rootTypeQName.getLocalPart());
3542             }
3543         }
3544         if (fCurrentType == null) {
3545             String typeName = (rootTypeQName.getPrefix().equals(XMLConstants.DEFAULT_NS_PREFIX)) ?
3546                     rootTypeQName.getLocalPart() :
3547                         rootTypeQName.getPrefix()+":"+rootTypeQName.getLocalPart();
3548                     reportSchemaError("cvc-type.1", new Object[] {typeName});
3549         }
3550     } // processRootTypeQName
3551 
3552     void processRootElementDeclQName(final javax.xml.namespace.QName rootElementDeclQName, final QName element) {
3553         String rootElementDeclNamespace = rootElementDeclQName.getNamespaceURI();
3554         // Add namespace to symbol table, to make sure it's interned.
3555         // This namespace may be later compared with other values using ==.
3556         rootElementDeclNamespace = fSymbolTable.addSymbol(rootElementDeclNamespace);
3557         if (rootElementDeclNamespace != null && rootElementDeclNamespace.equals(XMLConstants.NULL_NS_URI)) {
3558             rootElementDeclNamespace = null;
3559         }
3560         final SchemaGrammar grammarForRootElement = findSchemaGrammar(
3561                 XSDDescription.CONTEXT_ELEMENT, rootElementDeclNamespace, null, null, null);
3562         if (grammarForRootElement != null) {
3563             fCurrentElemDecl = grammarForRootElement.getGlobalElementDecl(rootElementDeclQName.getLocalPart());
3564         }
3565         if (fCurrentElemDecl == null) {
3566             String declName = (rootElementDeclQName.getPrefix().equals(XMLConstants.DEFAULT_NS_PREFIX)) ?
3567                     rootElementDeclQName.getLocalPart() :
3568                         rootElementDeclQName.getPrefix()+":"+rootElementDeclQName.getLocalPart();
3569                     reportSchemaError("cvc-elt.1.a", new Object[] {declName});
3570         }
3571         else {
3572             checkElementMatchesRootElementDecl(fCurrentElemDecl, element);
3573         }
3574     } // processRootElementDeclQName
3575 
3576     void checkElementMatchesRootElementDecl(final XSElementDecl rootElementDecl, final QName element) {
3577         // Report an error if the name of the element does
3578         // not match the name of the specified element declaration.
3579         if (element.localpart != rootElementDecl.fName ||
3580             element.uri != rootElementDecl.fTargetNamespace) {
3581             reportSchemaError("cvc-elt.1.b", new Object[] {element.rawname, rootElementDecl.fName});
3582         }
3583     } // checkElementMatchesRootElementDecl
3584 
3585     void reportSchemaError(String key, Object[] arguments) {
3586         if (fDoValidation)
3587             fXSIErrorReporter.reportError(
3588                 XSMessageFormatter.SCHEMA_DOMAIN,
3589                 key,
3590                 arguments,
3591                 XMLErrorReporter.SEVERITY_ERROR);
3592     }
3593 
3594     private String expectedStr(List<Object> expected) {
3595         StringBuilder ret = new StringBuilder("{");
3596         int size = expected.size();
3597         for (int i = 0; i < size; i++) {
3598             if (i > 0)
3599                 ret.append(", ");
3600             ret.append(expected.get(i).toString());
3601         }
3602         ret.append('}');
3603         return ret.toString();
3604     }
3605 
3606     /**********************************/
3607 
3608     // xpath matcher information
3609 
3610     /**
3611      * Stack of XPath matchers for identity constraints.
3612      *
3613      * @author Andy Clark, IBM
3614      */
3615     protected static class XPathMatcherStack {
3616 
3617         //
3618         // Data
3619         //
3620 
3621         /** Active matchers. */
3622         protected XPathMatcher[] fMatchers = new XPathMatcher[4];
3623 
3624         /** Count of active matchers. */
3625         protected int fMatchersCount;
3626 
3627         /** Offset stack for contexts. */
3628         protected IntStack fContextStack = new IntStack();
3629 
3630         //
3631         // Constructors
3632         //
3633 
3634         public XPathMatcherStack() {
3635         } // <init>()
3636 
3637         //
3638         // Public methods
3639         //
3640 
3641         /** Resets the XPath matcher stack. */
3642         public void clear() {
3643             for (int i = 0; i < fMatchersCount; i++) {
3644                 fMatchers[i] = null;
3645             }
3646             fMatchersCount = 0;
3647             fContextStack.clear();
3648         } // clear()
3649 
3650         /** Returns the size of the stack. */
3651         public int size() {
3652             return fContextStack.size();
3653         } // size():int
3654 
3655         /** Returns the count of XPath matchers. */
3656         public int getMatcherCount() {
3657             return fMatchersCount;
3658         } // getMatcherCount():int
3659 
3660         /** Adds a matcher. */
3661         public void addMatcher(XPathMatcher matcher) {
3662             ensureMatcherCapacity();
3663             fMatchers[fMatchersCount++] = matcher;
3664         } // addMatcher(XPathMatcher)
3665 
3666         /** Returns the XPath matcher at the specified index. */
3667         public XPathMatcher getMatcherAt(int index) {
3668             return fMatchers[index];
3669         } // getMatcherAt(index):XPathMatcher
3670 
3671         /** Pushes a new context onto the stack. */
3672         public void pushContext() {
3673             fContextStack.push(fMatchersCount);
3674         } // pushContext()
3675 
3676         /** Pops a context off of the stack. */
3677         public void popContext() {
3678             fMatchersCount = fContextStack.pop();
3679         } // popContext()
3680 
3681         //
3682         // Private methods
3683         //
3684 
3685         /** Ensures the size of the matchers array. */
3686         private void ensureMatcherCapacity() {
3687             if (fMatchersCount == fMatchers.length) {
3688                 XPathMatcher[] array = new XPathMatcher[fMatchers.length * 2];
3689                 System.arraycopy(fMatchers, 0, array, 0, fMatchers.length);
3690                 fMatchers = array;
3691             }
3692         } // ensureMatcherCapacity()
3693 
3694     } // class XPathMatcherStack
3695 
3696     // value store implementations
3697 
3698     /**
3699      * Value store implementation base class. There are specific subclasses
3700      * for handling unique, key, and keyref.
3701      *
3702      * @author Andy Clark, IBM
3703      */
3704     protected abstract class ValueStoreBase implements ValueStore {
3705 
3706         //
3707         // Data
3708         //
3709 
3710         /** Identity constraint. */
3711         protected IdentityConstraint fIdentityConstraint;
3712         protected int fFieldCount = 0;
3713         protected Field[] fFields = null;
3714         /** current data */
3715         protected Object[] fLocalValues = null;
3716         protected short[] fLocalValueTypes = null;
3717         protected ShortList[] fLocalItemValueTypes = null;
3718 
3719         /** Current data value count. */
3720         protected int fValuesCount;
3721 
3722         /** global data */
3723         public final Vector<Object> fValues = new Vector<>();
3724         public ShortVector fValueTypes = null;
3725         public Vector<ShortList> fItemValueTypes = null;
3726 
3727         private boolean fUseValueTypeVector = false;
3728         private int fValueTypesLength = 0;
3729         private short fValueType = 0;
3730 
3731         private boolean fUseItemValueTypeVector = false;
3732         private int fItemValueTypesLength = 0;
3733         private ShortList fItemValueType = null;
3734 
3735         /** buffer for error messages */
3736         final StringBuilder fTempBuffer = new StringBuilder();
3737 
3738         //
3739         // Constructors
3740         //
3741 
3742         /** Constructs a value store for the specified identity constraint. */
3743         protected ValueStoreBase(IdentityConstraint identityConstraint) {
3744             fIdentityConstraint = identityConstraint;
3745             fFieldCount = fIdentityConstraint.getFieldCount();
3746             fFields = new Field[fFieldCount];
3747             fLocalValues = new Object[fFieldCount];
3748             fLocalValueTypes = new short[fFieldCount];
3749             fLocalItemValueTypes = new ShortList[fFieldCount];
3750             for (int i = 0; i < fFieldCount; i++) {
3751                 fFields[i] = fIdentityConstraint.getFieldAt(i);
3752             }
3753         } // <init>(IdentityConstraint)
3754 
3755         //
3756         // Public methods
3757         //
3758 
3759         // destroys this ValueStore; useful when, for instance, a
3760         // locally-scoped ID constraint is involved.
3761         public void clear() {
3762             fValuesCount = 0;
3763             fUseValueTypeVector = false;
3764             fValueTypesLength = 0;
3765             fValueType = 0;
3766             fUseItemValueTypeVector = false;
3767             fItemValueTypesLength = 0;
3768             fItemValueType = null;
3769             fValues.setSize(0);
3770             if (fValueTypes != null) {
3771                 fValueTypes.clear();
3772             }
3773             if (fItemValueTypes != null) {
3774                 fItemValueTypes.setSize(0);
3775             }
3776         } // end clear():void
3777 
3778         // appends the contents of one ValueStore to those of us.
3779         public void append(ValueStoreBase newVal) {
3780             for (int i = 0; i < newVal.fValues.size(); i++) {
3781                 fValues.add(newVal.fValues.get(i));
3782             }
3783         } // append(ValueStoreBase)
3784 
3785         /** Start scope for value store. */
3786         public void startValueScope() {
3787             fValuesCount = 0;
3788             for (int i = 0; i < fFieldCount; i++) {
3789                 fLocalValues[i] = null;
3790                 fLocalValueTypes[i] = 0;
3791                 fLocalItemValueTypes[i] = null;
3792             }
3793         } // startValueScope()
3794 
3795         /** Ends scope for value store. */
3796         public void endValueScope() {
3797 
3798             if (fValuesCount == 0) {
3799                 if (fIdentityConstraint.getCategory() == IdentityConstraint.IC_KEY) {
3800                     String code = "AbsentKeyValue";
3801                     String eName = fIdentityConstraint.getElementName();
3802                     String cName = fIdentityConstraint.getIdentityConstraintName();
3803                     reportSchemaError(code, new Object[] { eName, cName });
3804                 }
3805                 return;
3806             }
3807 
3808             // Validation Rule: Identity-constraint Satisfied
3809             // 4.2 If the {identity-constraint category} is key, then all of the following must be true:
3810             // 4.2.1 The target node set and the qualified node set are equal, that is, every member of the
3811             // target node set is also a member of the qualified node set and vice versa.
3812             //
3813             // If the IDC is a key check whether we have all the fields.
3814             if (fValuesCount != fFieldCount) {
3815                 if (fIdentityConstraint.getCategory() == IdentityConstraint.IC_KEY) {
3816                     String code = "KeyNotEnoughValues";
3817                     UniqueOrKey key = (UniqueOrKey) fIdentityConstraint;
3818                     String eName = fIdentityConstraint.getElementName();
3819                     String cName = key.getIdentityConstraintName();
3820                     reportSchemaError(code, new Object[] { eName, cName });
3821                 }
3822                 return;
3823             }
3824 
3825         } // endValueScope()
3826 
3827         // This is needed to allow keyref's to look for matched keys
3828         // in the correct scope.  Unique and Key may also need to
3829         // override this method for purposes of their own.
3830         // This method is called whenever the DocumentFragment
3831         // of an ID Constraint goes out of scope.
3832         public void endDocumentFragment() {
3833         } // endDocumentFragment():void
3834 
3835         /**
3836          * Signals the end of the document. This is where the specific
3837          * instances of value stores can verify the integrity of the
3838          * identity constraints.
3839          */
3840         public void endDocument() {
3841         } // endDocument()
3842 
3843         //
3844         // ValueStore methods
3845         //
3846 
3847         /* reports an error if an element is matched
3848          * has nillable true and is matched by a key.
3849          */
3850 
3851         public void reportError(String key, Object[] args) {
3852             reportSchemaError(key, args);
3853         } // reportError(String,Object[])
3854 
3855         /**
3856          * Adds the specified value to the value store.
3857          *
3858          * @param field The field associated to the value. This reference
3859          *              is used to ensure that each field only adds a value
3860          *              once within a selection scope.
3861          * @param mayMatch a flag indiciating whether the field may be matched.
3862          * @param actualValue The value to add.
3863          * @param valueType Type of the value to add.
3864          * @param itemValueType If the value is a list, a list of types for each of the values in the list.
3865          */
3866         public void addValue(Field field, boolean mayMatch, Object actualValue, short valueType, ShortList itemValueType) {
3867             int i;
3868             for (i = fFieldCount - 1; i > -1; i--) {
3869                 if (fFields[i] == field) {
3870                     break;
3871                 }
3872             }
3873             // do we even know this field?
3874             if (i == -1) {
3875                 String code = "UnknownField";
3876                 String eName = fIdentityConstraint.getElementName();
3877                 String cName = fIdentityConstraint.getIdentityConstraintName();
3878                 reportSchemaError(code, new Object[] { field.toString(), eName, cName });
3879                 return;
3880             }
3881             if (!mayMatch) {
3882                 String code = "FieldMultipleMatch";
3883                 String cName = fIdentityConstraint.getIdentityConstraintName();
3884                 reportSchemaError(code, new Object[] { field.toString(), cName });
3885             }
3886             else {
3887                 fValuesCount++;
3888             }
3889             fLocalValues[i] = actualValue;
3890             fLocalValueTypes[i] = valueType;
3891             fLocalItemValueTypes[i] = itemValueType;
3892             if (fValuesCount == fFieldCount) {
3893                 checkDuplicateValues();
3894                 // store values
3895                 for (i = 0; i < fFieldCount; i++) {
3896                     fValues.add(fLocalValues[i]);
3897                     addValueType(fLocalValueTypes[i]);
3898                     addItemValueType(fLocalItemValueTypes[i]);
3899                 }
3900             }
3901         } // addValue(String,Field)
3902 
3903         /**
3904          * Returns true if this value store contains the locally scoped value stores
3905          */
3906         public boolean contains() {
3907             // REVISIT: we can improve performance by using hash codes, instead of
3908             // traversing global vector that could be quite large.
3909             int next = 0;
3910             final int size = fValues.size();
3911             LOOP : for (int i = 0; i < size; i = next) {
3912                 next = i + fFieldCount;
3913                 for (int j = 0; j < fFieldCount; j++) {
3914                     Object value1 = fLocalValues[j];
3915                     Object value2 = fValues.get(i);
3916                     short valueType1 = fLocalValueTypes[j];
3917                     short valueType2 = getValueTypeAt(i);
3918                     if (value1 == null || value2 == null || valueType1 != valueType2 || !(value1.equals(value2))) {
3919                         continue LOOP;
3920                     }
3921                     else if(valueType1 == XSConstants.LIST_DT || valueType1 == XSConstants.LISTOFUNION_DT) {
3922                         ShortList list1 = fLocalItemValueTypes[j];
3923                         ShortList list2 = getItemValueTypeAt(i);
3924                         if(list1 == null || list2 == null || !list1.equals(list2))
3925                             continue LOOP;
3926                     }
3927                     i++;
3928                 }
3929                 // found it
3930                 return true;
3931             }
3932             // didn't find it
3933             return false;
3934         } // contains():boolean
3935 
3936         /**
3937          * Returns -1 if this value store contains the specified
3938          * values, otherwise the index of the first field in the
3939          * key sequence.
3940          */
3941         public int contains(ValueStoreBase vsb) {
3942 
3943             final Vector<Object> values = vsb.fValues;
3944             final int size1 = values.size();
3945             if (fFieldCount <= 1) {
3946                 for (int i = 0; i < size1; ++i) {
3947                     short val = vsb.getValueTypeAt(i);
3948                     if (!valueTypeContains(val) || !fValues.contains(values.get(i))) {
3949                         return i;
3950                     }
3951                     else if(val == XSConstants.LIST_DT || val == XSConstants.LISTOFUNION_DT) {
3952                         ShortList list1 = vsb.getItemValueTypeAt(i);
3953                         if (!itemValueTypeContains(list1)) {
3954                             return i;
3955                         }
3956                     }
3957                 }
3958             }
3959             /** Handle n-tuples. **/
3960             else {
3961                 final int size2 = fValues.size();
3962                 /** Iterate over each set of fields. **/
3963                 OUTER: for (int i = 0; i < size1; i += fFieldCount) {
3964                     /** Check whether this set is contained in the value store. **/
3965                     INNER: for (int j = 0; j < size2; j += fFieldCount) {
3966                         for (int k = 0; k < fFieldCount; ++k) {
3967                             final Object value1 = values.get(i+k);
3968                             final Object value2 = fValues.get(j+k);
3969                             final short valueType1 = vsb.getValueTypeAt(i+k);
3970                             final short valueType2 = getValueTypeAt(j+k);
3971                             if (value1 != value2 && (valueType1 != valueType2 || value1 == null || !value1.equals(value2))) {
3972                                 continue INNER;
3973                             }
3974                             else if(valueType1 == XSConstants.LIST_DT || valueType1 == XSConstants.LISTOFUNION_DT) {
3975                                 ShortList list1 = vsb.getItemValueTypeAt(i+k);
3976                                 ShortList list2 = getItemValueTypeAt(j+k);
3977                                 if (list1 == null || list2 == null || !list1.equals(list2)) {
3978                                     continue INNER;
3979                                 }
3980                             }
3981                         }
3982                         continue OUTER;
3983                     }
3984                     return i;
3985                 }
3986             }
3987             return -1;
3988 
3989         } // contains(Vector):Object
3990 
3991         //
3992         // Protected methods
3993         //
3994 
3995         protected void checkDuplicateValues() {
3996             // no-op
3997         } // duplicateValue(Map)
3998 
3999         /** Returns a string of the specified values. */
4000         protected String toString(Object[] values) {
4001 
4002             // no values
4003             int size = values.length;
4004             if (size == 0) {
4005                 return "";
4006             }
4007 
4008             fTempBuffer.setLength(0);
4009 
4010             // construct value string
4011             for (int i = 0; i < size; i++) {
4012                 if (i > 0) {
4013                     fTempBuffer.append(',');
4014                 }
4015                 fTempBuffer.append(values[i]);
4016             }
4017             return fTempBuffer.toString();
4018 
4019         } // toString(Object[]):String
4020 
4021         /** Returns a string of the specified values. */
4022         protected String toString(Vector<Object> values, int start, int length) {
4023 
4024             // no values
4025             if (length == 0) {
4026                 return "";
4027             }
4028 
4029             // one value
4030             if (length == 1) {
4031                 return String.valueOf(values.get(start));
4032             }
4033 
4034             // construct value string
4035             StringBuilder str = new StringBuilder();
4036             for (int i = 0; i < length; i++) {
4037                 if (i > 0) {
4038                     str.append(',');
4039                 }
4040                 str.append(values.get(start + i));
4041             }
4042             return str.toString();
4043 
4044         } // toString(Vector,int,int):String
4045 
4046         //
4047         // Object methods
4048         //
4049 
4050         /** Returns a string representation of this object. */
4051         public String toString() {
4052             String s = super.toString();
4053             int index1 = s.lastIndexOf('$');
4054             if (index1 != -1) {
4055                 s = s.substring(index1 + 1);
4056             }
4057             int index2 = s.lastIndexOf('.');
4058             if (index2 != -1) {
4059                 s = s.substring(index2 + 1);
4060             }
4061             return s + '[' + fIdentityConstraint + ']';
4062         } // toString():String
4063 
4064         //
4065         // Private methods
4066         //
4067 
4068         private void addValueType(short type) {
4069             if (fUseValueTypeVector) {
4070                 fValueTypes.add(type);
4071             }
4072             else if (fValueTypesLength++ == 0) {
4073                 fValueType = type;
4074             }
4075             else if (fValueType != type) {
4076                 fUseValueTypeVector = true;
4077                 if (fValueTypes == null) {
4078                     fValueTypes = new ShortVector(fValueTypesLength * 2);
4079                 }
4080                 for (int i = 1; i < fValueTypesLength; ++i) {
4081                     fValueTypes.add(fValueType);
4082                 }
4083                 fValueTypes.add(type);
4084             }
4085         }
4086 
4087         private short getValueTypeAt(int index) {
4088             if (fUseValueTypeVector) {
4089                 return fValueTypes.valueAt(index);
4090             }
4091             return fValueType;
4092         }
4093 
4094         private boolean valueTypeContains(short value) {
4095             if (fUseValueTypeVector) {
4096                 return fValueTypes.contains(value);
4097             }
4098             return fValueType == value;
4099         }
4100 
4101         private void addItemValueType(ShortList itemValueType) {
4102             if (fUseItemValueTypeVector) {
4103                 fItemValueTypes.add(itemValueType);
4104             }
4105             else if (fItemValueTypesLength++ == 0) {
4106                 fItemValueType = itemValueType;
4107             }
4108             else if (!(fItemValueType == itemValueType ||
4109                     (fItemValueType != null && fItemValueType.equals(itemValueType)))) {
4110                 fUseItemValueTypeVector = true;
4111                 if (fItemValueTypes == null) {
4112                     fItemValueTypes = new Vector<>(fItemValueTypesLength * 2);
4113                 }
4114                 for (int i = 1; i < fItemValueTypesLength; ++i) {
4115                     fItemValueTypes.add(fItemValueType);
4116                 }
4117                 fItemValueTypes.add(itemValueType);
4118             }
4119         }
4120 
4121         private ShortList getItemValueTypeAt(int index) {
4122             if (fUseItemValueTypeVector) {
4123                 return fItemValueTypes.get(index);
4124             }
4125             return fItemValueType;
4126         }
4127 
4128         private boolean itemValueTypeContains(ShortList value) {
4129             if (fUseItemValueTypeVector) {
4130                 return fItemValueTypes.contains(value);
4131             }
4132             return fItemValueType == value ||
4133                 (fItemValueType != null && fItemValueType.equals(value));
4134         }
4135 
4136     } // class ValueStoreBase
4137 
4138     /**
4139      * Unique value store.
4140      *
4141      * @author Andy Clark, IBM
4142      */
4143     protected class UniqueValueStore extends ValueStoreBase {
4144 
4145         //
4146         // Constructors
4147         //
4148 
4149         /** Constructs a unique value store. */
4150         public UniqueValueStore(UniqueOrKey unique) {
4151             super(unique);
4152         } // <init>(Unique)
4153 
4154         //
4155         // ValueStoreBase protected methods
4156         //
4157 
4158         /**
4159          * Called when a duplicate value is added.
4160          */
4161         protected void checkDuplicateValues() {
4162             // is this value as a group duplicated?
4163             if (contains()) {
4164                 String code = "DuplicateUnique";
4165                 String value = toString(fLocalValues);
4166                 String eName = fIdentityConstraint.getElementName();
4167                 String cName = fIdentityConstraint.getIdentityConstraintName();
4168                 reportSchemaError(code, new Object[] { value, eName, cName });
4169             }
4170         } // duplicateValue(Map)
4171 
4172     } // class UniqueValueStore
4173 
4174     /**
4175      * Key value store.
4176      *
4177      * @author Andy Clark, IBM
4178      */
4179     protected class KeyValueStore extends ValueStoreBase {
4180 
4181         // REVISIT: Implement a more efficient storage mechanism. -Ac
4182 
4183         //
4184         // Constructors
4185         //
4186 
4187         /** Constructs a key value store. */
4188         public KeyValueStore(UniqueOrKey key) {
4189             super(key);
4190         } // <init>(Key)
4191 
4192         //
4193         // ValueStoreBase protected methods
4194         //
4195 
4196         /**
4197          * Called when a duplicate value is added.
4198          */
4199         protected void checkDuplicateValues() {
4200             if (contains()) {
4201                 String code = "DuplicateKey";
4202                 String value = toString(fLocalValues);
4203                 String eName = fIdentityConstraint.getElementName();
4204                 String cName = fIdentityConstraint.getIdentityConstraintName();
4205                 reportSchemaError(code, new Object[] { value, eName, cName });
4206             }
4207         } // duplicateValue(Map)
4208 
4209     } // class KeyValueStore
4210 
4211     /**
4212      * Key reference value store.
4213      *
4214      * @author Andy Clark, IBM
4215      */
4216     protected class KeyRefValueStore extends ValueStoreBase {
4217 
4218         //
4219         // Data
4220         //
4221 
4222         /** Key value store. */
4223         protected ValueStoreBase fKeyValueStore;
4224 
4225         //
4226         // Constructors
4227         //
4228 
4229         /** Constructs a key value store. */
4230         public KeyRefValueStore(KeyRef keyRef, KeyValueStore keyValueStore) {
4231             super(keyRef);
4232             fKeyValueStore = keyValueStore;
4233         } // <init>(KeyRef)
4234 
4235         //
4236         // ValueStoreBase methods
4237         //
4238 
4239         // end the value Scope; here's where we have to tie
4240         // up keyRef loose ends.
4241         public void endDocumentFragment() {
4242 
4243             // do all the necessary management...
4244             super.endDocumentFragment();
4245 
4246             // verify references
4247             // get the key store corresponding (if it exists):
4248             fKeyValueStore = fValueStoreCache.fGlobalIDConstraintMap.get(
4249                     ((KeyRef) fIdentityConstraint).getKey());
4250 
4251             if (fKeyValueStore == null) {
4252                 // report error
4253                 String code = "KeyRefOutOfScope";
4254                 String value = fIdentityConstraint.toString();
4255                 reportSchemaError(code, new Object[] { value });
4256                 return;
4257             }
4258             int errorIndex = fKeyValueStore.contains(this);
4259             if (errorIndex != -1) {
4260                 String code = "KeyNotFound";
4261                 String values = toString(fValues, errorIndex, fFieldCount);
4262                 String element = fIdentityConstraint.getElementName();
4263                 String name = fIdentityConstraint.getName();
4264                 reportSchemaError(code, new Object[] { name, values, element });
4265             }
4266 
4267         } // endDocumentFragment()
4268 
4269         /** End document. */
4270         public void endDocument() {
4271             super.endDocument();
4272 
4273         } // endDocument()
4274 
4275     } // class KeyRefValueStore
4276 
4277     // value store management
4278 
4279     /**
4280      * Value store cache. This class is used to store the values for
4281      * identity constraints.
4282      *
4283      * @author Andy Clark, IBM
4284      */
4285     protected class ValueStoreCache {
4286 
4287         //
4288         // Data
4289         //
4290         final LocalIDKey fLocalId = new LocalIDKey();
4291         // values stores
4292 
4293         /** stores all global Values stores. */
4294         protected final List<ValueStoreBase> fValueStores = new ArrayList<>();
4295 
4296         /**
4297          * Values stores associated to specific identity constraints.
4298          * This map maps IdentityConstraints and
4299          * the 0-based element on which their selectors first matched to
4300          * a corresponding ValueStore.  This should take care
4301          * of all cases, including where ID constraints with
4302          * descendant-or-self axes occur on recursively-defined
4303          * elements.
4304          */
4305         protected final Map<LocalIDKey, ValueStoreBase>
4306                 fIdentityConstraint2ValueStoreMap = new HashMap<>();
4307 
4308         // sketch of algorithm:
4309         // - when a constraint is first encountered, its
4310         //   values are stored in the (local) fIdentityConstraint2ValueStoreMap;
4311         // - Once it is validated (i.e., when it goes out of scope),
4312         //   its values are merged into the fGlobalIDConstraintMap;
4313         // - as we encounter keyref's, we look at the global table to
4314         //    validate them.
4315         //
4316         // The fGlobalIDMapStack has the following structure:
4317         // - validation always occurs against the fGlobalIDConstraintMap
4318         // (which comprises all the "eligible" id constraints);
4319         // When an endElement is found, this Map is merged with the one
4320         // below in the stack.
4321         // When a start tag is encountered, we create a new
4322         // fGlobalIDConstraintMap.
4323         // i.e., the top of the fGlobalIDMapStack always contains
4324         // the preceding siblings' eligible id constraints;
4325         // the fGlobalIDConstraintMap contains descendants+self.
4326         // keyrefs can only match descendants+self.
4327         protected final Stack<Map<IdentityConstraint, ValueStoreBase>>
4328                 fGlobalMapStack = new Stack<>();
4329         protected final Map<IdentityConstraint, ValueStoreBase>
4330                 fGlobalIDConstraintMap = new HashMap<>();
4331 
4332         //
4333         // Constructors
4334         //
4335 
4336         /** Default constructor. */
4337         public ValueStoreCache() {
4338         } // <init>()
4339 
4340         //
4341         // Public methods
4342         //
4343 
4344         /** Resets the identity constraint cache. */
4345         public void startDocument() {
4346             fValueStores.clear();
4347             fIdentityConstraint2ValueStoreMap.clear();
4348             fGlobalIDConstraintMap.clear();
4349             fGlobalMapStack.removeAllElements();
4350         } // startDocument()
4351 
4352         // startElement:  pushes the current fGlobalIDConstraintMap
4353         // onto fGlobalMapStack and clears fGlobalIDConstraint map.
4354         @SuppressWarnings("unchecked")
4355         public void startElement() {
4356             // only clone the map when there are elements
4357             if (fGlobalIDConstraintMap.size() > 0)
4358                 fGlobalMapStack.push((Map<IdentityConstraint, ValueStoreBase>)
4359                         ((HashMap<IdentityConstraint, ValueStoreBase>)fGlobalIDConstraintMap).clone());
4360             else
4361                 fGlobalMapStack.push(null);
4362             fGlobalIDConstraintMap.clear();
4363         } // startElement(void)
4364 
4365         /** endElement():  merges contents of fGlobalIDConstraintMap with the
4366          * top of fGlobalMapStack into fGlobalIDConstraintMap.
4367          */
4368         public void endElement() {
4369             if (fGlobalMapStack.isEmpty()) {
4370                 return; // must be an invalid doc!
4371             }
4372             Map<IdentityConstraint, ValueStoreBase> oldMap = fGlobalMapStack.pop();
4373             // return if there is no element
4374             if (oldMap == null) {
4375                 return;
4376             }
4377 
4378             for (Map.Entry<IdentityConstraint, ValueStoreBase> entry : oldMap.entrySet()) {
4379                 IdentityConstraint id = entry.getKey();
4380                 ValueStoreBase oldVal = entry.getValue();
4381                 if (oldVal != null) {
4382                     ValueStoreBase currVal = fGlobalIDConstraintMap.get(id);
4383                     if (currVal == null) {
4384                         fGlobalIDConstraintMap.put(id, oldVal);
4385                     }
4386                     else if (currVal != oldVal) {
4387                         currVal.append(oldVal);
4388                     }
4389                 }
4390             }
4391         } // endElement()
4392 
4393         /**
4394          * Initializes the value stores for the specified element
4395          * declaration.
4396          */
4397         public void initValueStoresFor(XSElementDecl eDecl, FieldActivator activator) {
4398             // initialize value stores for unique fields
4399             IdentityConstraint[] icArray = eDecl.fIDConstraints;
4400             int icCount = eDecl.fIDCPos;
4401             for (int i = 0; i < icCount; i++) {
4402                 switch (icArray[i].getCategory()) {
4403                     case (IdentityConstraint.IC_UNIQUE) :
4404                         // initialize value stores for unique fields
4405                         UniqueOrKey unique = (UniqueOrKey) icArray[i];
4406                         LocalIDKey toHash = new LocalIDKey(unique, fElementDepth);
4407                         UniqueValueStore uniqueValueStore =
4408                             (UniqueValueStore) fIdentityConstraint2ValueStoreMap.get(toHash);
4409                         if (uniqueValueStore == null) {
4410                             uniqueValueStore = new UniqueValueStore(unique);
4411                             fIdentityConstraint2ValueStoreMap.put(toHash, uniqueValueStore);
4412                         } else {
4413                             uniqueValueStore.clear();
4414                         }
4415                         fValueStores.add(uniqueValueStore);
4416                         activateSelectorFor(icArray[i]);
4417                         break;
4418                     case (IdentityConstraint.IC_KEY) :
4419                         // initialize value stores for key fields
4420                         UniqueOrKey key = (UniqueOrKey) icArray[i];
4421                         toHash = new LocalIDKey(key, fElementDepth);
4422                         KeyValueStore keyValueStore =
4423                             (KeyValueStore) fIdentityConstraint2ValueStoreMap.get(toHash);
4424                         if (keyValueStore == null) {
4425                             keyValueStore = new KeyValueStore(key);
4426                             fIdentityConstraint2ValueStoreMap.put(toHash, keyValueStore);
4427                         } else {
4428                             keyValueStore.clear();
4429                         }
4430                         fValueStores.add(keyValueStore);
4431                         activateSelectorFor(icArray[i]);
4432                         break;
4433                     case (IdentityConstraint.IC_KEYREF) :
4434                         // initialize value stores for keyRef fields
4435                         KeyRef keyRef = (KeyRef) icArray[i];
4436                         toHash = new LocalIDKey(keyRef, fElementDepth);
4437                         KeyRefValueStore keyRefValueStore =
4438                             (KeyRefValueStore) fIdentityConstraint2ValueStoreMap.get(toHash);
4439                         if (keyRefValueStore == null) {
4440                             keyRefValueStore = new KeyRefValueStore(keyRef, null);
4441                             fIdentityConstraint2ValueStoreMap.put(toHash, keyRefValueStore);
4442                         } else {
4443                             keyRefValueStore.clear();
4444                         }
4445                         fValueStores.add(keyRefValueStore);
4446                         activateSelectorFor(icArray[i]);
4447                         break;
4448                 }
4449             }
4450         } // initValueStoresFor(XSElementDecl)
4451 
4452         /** Returns the value store associated to the specified IdentityConstraint. */
4453         public ValueStoreBase getValueStoreFor(IdentityConstraint id, int initialDepth) {
4454             fLocalId.fDepth = initialDepth;
4455             fLocalId.fId = id;
4456             return fIdentityConstraint2ValueStoreMap.get(fLocalId);
4457         } // getValueStoreFor(IdentityConstraint, int):ValueStoreBase
4458 
4459         /** Returns the global value store associated to the specified IdentityConstraint. */
4460         public ValueStoreBase getGlobalValueStoreFor(IdentityConstraint id) {
4461             return fGlobalIDConstraintMap.get(id);
4462         } // getValueStoreFor(IdentityConstraint):ValueStoreBase
4463 
4464         // This method takes the contents of the (local) ValueStore
4465         // associated with id and moves them into the global
4466         // map, if id is a <unique> or a <key>.
4467         // If it's a <keyRef>, then we leave it for later.
4468         public void transplant(IdentityConstraint id, int initialDepth) {
4469             fLocalId.fDepth = initialDepth;
4470             fLocalId.fId = id;
4471             ValueStoreBase newVals = fIdentityConstraint2ValueStoreMap.get(fLocalId);
4472             if (id.getCategory() == IdentityConstraint.IC_KEYREF)
4473                 return;
4474             ValueStoreBase currVals = fGlobalIDConstraintMap.get(id);
4475             if (currVals != null) {
4476                 currVals.append(newVals);
4477                 fGlobalIDConstraintMap.put(id, currVals);
4478             } else
4479                 fGlobalIDConstraintMap.put(id, newVals);
4480 
4481         } // transplant(id)
4482 
4483         /** Check identity constraints. */
4484         public void endDocument() {
4485 
4486             for (ValueStoreBase valueStore : fValueStores) {
4487                 valueStore.endDocument();
4488             }
4489 
4490         } // endDocument()
4491 
4492         //
4493         // Object methods
4494         //
4495 
4496         /** Returns a string representation of this object. */
4497         public String toString() {
4498             String s = super.toString();
4499             int index1 = s.lastIndexOf('$');
4500             if (index1 != -1) {
4501                 return s.substring(index1 + 1);
4502             }
4503             int index2 = s.lastIndexOf('.');
4504             if (index2 != -1) {
4505                 return s.substring(index2 + 1);
4506             }
4507             return s;
4508         } // toString():String
4509 
4510     } // class ValueStoreCache
4511 
4512     // the purpose of this class is to enable IdentityConstraint,int
4513     // pairs to be used easily as keys in Maps.
4514     protected static final class LocalIDKey {
4515 
4516         public IdentityConstraint fId;
4517         public int fDepth;
4518 
4519         public LocalIDKey() {
4520         }
4521 
4522         public LocalIDKey(IdentityConstraint id, int depth) {
4523             fId = id;
4524             fDepth = depth;
4525         } // init(IdentityConstraint, int)
4526 
4527         // object method
4528         public int hashCode() {
4529             return fId.hashCode() + fDepth;
4530         }
4531 
4532         public boolean equals(Object localIDKey) {
4533             if (localIDKey instanceof LocalIDKey) {
4534                 LocalIDKey lIDKey = (LocalIDKey) localIDKey;
4535                 return (lIDKey.fId == fId && lIDKey.fDepth == fDepth);
4536             }
4537             return false;
4538         }
4539     } // class LocalIDKey
4540 
4541     /**
4542      * A simple vector for <code>short</code>s.
4543      */
4544     protected static final class ShortVector {
4545 
4546         //
4547         // Data
4548         //
4549 
4550         /** Current length. */
4551         private int fLength;
4552 
4553         /** Data. */
4554         private short[] fData;
4555 
4556         //
4557         // Constructors
4558         //
4559 
4560         public ShortVector() {}
4561 
4562         public ShortVector(int initialCapacity) {
4563             fData = new short[initialCapacity];
4564         }
4565 
4566         //
4567         // Public methods
4568         //
4569 
4570         /** Returns the length of the vector. */
4571         public int length() {
4572             return fLength;
4573         }
4574 
4575         /** Adds the value to the vector. */
4576         public void add(short value) {
4577             ensureCapacity(fLength + 1);
4578             fData[fLength++] = value;
4579         }
4580 
4581         /** Returns the short value at the specified position in the vector. */
4582         public short valueAt(int position) {
4583             return fData[position];
4584         }
4585 
4586         /** Clears the vector. */
4587         public void clear() {
4588             fLength = 0;
4589         }
4590 
4591         /** Returns whether the short is contained in the vector. */
4592         public boolean contains(short value) {
4593             for (int i = 0; i < fLength; ++i) {
4594                 if (fData[i] == value) {
4595                     return true;
4596                 }
4597             }
4598             return false;
4599         }
4600 
4601         //
4602         // Private methods
4603         //
4604 
4605         /** Ensures capacity. */
4606         private void ensureCapacity(int size) {
4607             if (fData == null) {
4608                 fData = new short[8];
4609             }
4610             else if (fData.length <= size) {
4611                 short[] newdata = new short[fData.length * 2];
4612                 System.arraycopy(fData, 0, newdata, 0, fData.length);
4613                 fData = newdata;
4614             }
4615         }
4616     }
4617 
4618 } // class SchemaValidator