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