1 /*
   2  * Copyright (c) 2017, 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 
  21 package com.sun.org.apache.xerces.internal.impl.xs.traversers;
  22 
  23 import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeValueException;
  24 import com.sun.org.apache.xerces.internal.impl.dv.XSFacets;
  25 import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType;
  26 import com.sun.org.apache.xerces.internal.impl.validation.ValidationState;
  27 import com.sun.org.apache.xerces.internal.impl.xs.SchemaGrammar;
  28 import com.sun.org.apache.xerces.internal.impl.xs.SchemaSymbols;
  29 import com.sun.org.apache.xerces.internal.impl.xs.XSAnnotationImpl;
  30 import com.sun.org.apache.xerces.internal.impl.xs.XSAttributeGroupDecl;
  31 import com.sun.org.apache.xerces.internal.impl.xs.XSAttributeUseImpl;
  32 import com.sun.org.apache.xerces.internal.impl.xs.XSComplexTypeDecl;
  33 import com.sun.org.apache.xerces.internal.impl.xs.XSElementDecl;
  34 import com.sun.org.apache.xerces.internal.impl.xs.XSParticleDecl;
  35 import com.sun.org.apache.xerces.internal.impl.xs.XSWildcardDecl;
  36 import com.sun.org.apache.xerces.internal.impl.xs.util.XInt;
  37 import com.sun.org.apache.xerces.internal.impl.xs.util.XSObjectListImpl;
  38 import com.sun.org.apache.xerces.internal.util.DOMUtil;
  39 import com.sun.org.apache.xerces.internal.util.NamespaceSupport;
  40 import com.sun.org.apache.xerces.internal.util.SymbolTable;
  41 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
  42 import com.sun.org.apache.xerces.internal.xni.QName;
  43 import com.sun.org.apache.xerces.internal.xs.XSAttributeUse;
  44 import com.sun.org.apache.xerces.internal.xs.XSObjectList;
  45 import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
  46 import java.util.ArrayList;
  47 import java.util.List;
  48 import java.util.Locale;
  49 import org.w3c.dom.Element;
  50 
  51 /**
  52  * Class <code>XSDAbstractTraverser</code> serves as the base class for all
  53  * other <code>XSD???Traverser</code>s. It holds the common data and provide
  54  * a unified way to initialize these data.
  55  *
  56  * @xerces.internal
  57  *
  58  * @author Elena Litani, IBM
  59  * @author Rahul Srivastava, Sun Microsystems Inc.
  60  * @author Neeraj Bajaj, Sun Microsystems Inc.
  61  *
  62  * @LastModified: Oct 2017
  63  */
  64 abstract class XSDAbstractTraverser {
  65 
  66     protected static final String NO_NAME      = "(no name)";
  67 
  68     // Flags for checkOccurrences to indicate any special
  69     // restrictions on minOccurs and maxOccurs relating to "all".
  70     //    NOT_ALL_CONTEXT    - not processing an <all>
  71     //    PROCESSING_ALL_EL  - processing an <element> in an <all>
  72     //    GROUP_REF_WITH_ALL - processing <group> reference that contained <all>
  73     //    CHILD_OF_GROUP     - processing a child of a model group definition
  74     //    PROCESSING_ALL_GP  - processing an <all> group itself
  75 
  76     protected static final int NOT_ALL_CONTEXT    = 0;
  77     protected static final int PROCESSING_ALL_EL  = 1;
  78     protected static final int GROUP_REF_WITH_ALL = 2;
  79     protected static final int CHILD_OF_GROUP     = 4;
  80     protected static final int PROCESSING_ALL_GP  = 8;
  81 
  82     //Shared data
  83     protected XSDHandler            fSchemaHandler = null;
  84     protected SymbolTable           fSymbolTable = null;
  85     protected XSAttributeChecker    fAttrChecker = null;
  86     protected boolean               fValidateAnnotations = false;
  87 
  88     // used to validate default/fixed attribute values
  89     ValidationState fValidationState = new ValidationState();
  90 
  91     XSDAbstractTraverser (XSDHandler handler,
  92             XSAttributeChecker attrChecker) {
  93         fSchemaHandler = handler;
  94         fAttrChecker = attrChecker;
  95     }
  96 
  97     void reset(SymbolTable symbolTable, boolean validateAnnotations, Locale locale) {
  98         fSymbolTable = symbolTable;
  99         fValidateAnnotations = validateAnnotations;
 100         fValidationState.setExtraChecking(false);
 101         fValidationState.setSymbolTable(symbolTable);
 102         fValidationState.setLocale(locale);
 103     }
 104 
 105     // traverse the annotation declaration
 106     // REVISIT: how to pass the parentAttrs? as DOM attributes?
 107     //          as name/value pairs (string)? in parsed form?
 108     // @return XSAnnotationImpl object
 109     XSAnnotationImpl traverseAnnotationDecl(Element annotationDecl, Object[] parentAttrs,
 110             boolean isGlobal, XSDocumentInfo schemaDoc) {
 111         // General Attribute Checking
 112         Object[] attrValues = fAttrChecker.checkAttributes(annotationDecl, isGlobal, schemaDoc);
 113         fAttrChecker.returnAttrArray(attrValues, schemaDoc);
 114 
 115         String contents = DOMUtil.getAnnotation(annotationDecl);
 116         Element child = DOMUtil.getFirstChildElement(annotationDecl);
 117         if (child != null) {
 118             do {
 119                 String name = DOMUtil.getLocalName(child);
 120 
 121                 // the only valid children of "annotation" are
 122                 // "appinfo" and "documentation"
 123                 if (!((name.equals(SchemaSymbols.ELT_APPINFO)) ||
 124                         (name.equals(SchemaSymbols.ELT_DOCUMENTATION)))) {
 125                     reportSchemaError("src-annotation", new Object[]{name}, child);
 126                 }
 127                 else {
 128                     // General Attribute Checking
 129                     // There is no difference between global or local appinfo/documentation,
 130                     // so we assume it's always global.
 131                     attrValues = fAttrChecker.checkAttributes(child, true, schemaDoc);
 132                     fAttrChecker.returnAttrArray(attrValues, schemaDoc);
 133                 }
 134 
 135                 child = DOMUtil.getNextSiblingElement(child);
 136             }
 137             while (child != null);
 138         }
 139         // if contents was null, must have been some kind of error;
 140         // nothing to contribute to PSVI
 141         if (contents == null) return null;
 142 
 143         // find the grammar; fSchemaHandler must be known!
 144         SchemaGrammar grammar = fSchemaHandler.getGrammar(schemaDoc.fTargetNamespace);
 145         // fish out local attributes passed from parent
 146         @SuppressWarnings("unchecked")
 147         List<String> annotationLocalAttrs = (ArrayList<String>)parentAttrs[XSAttributeChecker.ATTIDX_NONSCHEMA];
 148         // optimize for case where there are no local attributes
 149         if(annotationLocalAttrs != null && !annotationLocalAttrs.isEmpty()) {
 150             StringBuilder localStrBuffer = new StringBuilder(64);
 151             localStrBuffer.append(" ");
 152             //ArrayList<>should contain rawname value pairs
 153             int i = 0;
 154             while (i < annotationLocalAttrs.size()) {
 155                 String rawname = annotationLocalAttrs.get(i++);
 156                 int colonIndex = rawname.indexOf(':');
 157                 String prefix, localpart;
 158                 if (colonIndex == -1) {
 159                     prefix = "";
 160                     localpart = rawname;
 161                 }
 162                 else {
 163                     prefix = rawname.substring(0,colonIndex);
 164                     localpart = rawname.substring(colonIndex+1);
 165                 }
 166                 String uri = schemaDoc.fNamespaceSupport.getURI(fSymbolTable.addSymbol(prefix));
 167                 if (annotationDecl.getAttributeNS(uri, localpart).length() != 0) {
 168                     i++; // skip the next value, too
 169                     continue;
 170                 }
 171                 localStrBuffer.append(rawname)
 172                 .append("=\"");
 173                 String value = annotationLocalAttrs.get(i++);
 174                 // search for pesky "s and <s within attr value:
 175                 value = processAttValue(value);
 176                 localStrBuffer.append(value)
 177                 .append("\" ");
 178             }
 179             // and now splice it into place; immediately after the annotation token, for simplicity's sake
 180             StringBuilder contentBuffer = new StringBuilder(contents.length() + localStrBuffer.length());
 181             int annotationTokenEnd = contents.indexOf(SchemaSymbols.ELT_ANNOTATION);
 182             // annotation must occur somewhere or we're in big trouble...
 183             if(annotationTokenEnd == -1) return null;
 184             annotationTokenEnd += SchemaSymbols.ELT_ANNOTATION.length();
 185             contentBuffer.append(contents.substring(0,annotationTokenEnd));
 186             contentBuffer.append(localStrBuffer.toString());
 187             contentBuffer.append(contents.substring(annotationTokenEnd, contents.length()));
 188             final String annotation = contentBuffer.toString();
 189             if (fValidateAnnotations) {
 190                 schemaDoc.addAnnotation(new XSAnnotationInfo(annotation, annotationDecl));
 191             }
 192             return new XSAnnotationImpl(annotation, grammar);
 193         } else {
 194             if (fValidateAnnotations) {
 195                 schemaDoc.addAnnotation(new XSAnnotationInfo(contents, annotationDecl));
 196             }
 197             return new XSAnnotationImpl(contents, grammar);
 198         }
 199 
 200     }
 201 
 202     XSAnnotationImpl traverseSyntheticAnnotation(Element annotationParent, String initialContent,
 203             Object[] parentAttrs, boolean isGlobal, XSDocumentInfo schemaDoc) {
 204 
 205         String contents = initialContent;
 206 
 207         // find the grammar; fSchemaHandler must be known!
 208         SchemaGrammar grammar = fSchemaHandler.getGrammar(schemaDoc.fTargetNamespace);
 209         // fish out local attributes passed from parent
 210         @SuppressWarnings("unchecked")
 211         List<String> annotationLocalAttrs = (ArrayList<String>)parentAttrs[XSAttributeChecker.ATTIDX_NONSCHEMA];
 212         // optimize for case where there are no local attributes
 213         if (annotationLocalAttrs != null && !annotationLocalAttrs.isEmpty()) {
 214             StringBuilder localStrBuffer = new StringBuilder(64);
 215             localStrBuffer.append(" ");
 216             //ArrayList<>should contain rawname value pairs
 217             int i = 0;
 218             while (i < annotationLocalAttrs.size()) {
 219                 String rawname = annotationLocalAttrs.get(i++);
 220                 int colonIndex = rawname.indexOf(':');
 221                 String prefix, localpart;
 222                 if (colonIndex == -1) {
 223                     prefix = "";
 224                     localpart = rawname;
 225                 }
 226                 else {
 227                     prefix = rawname.substring(0,colonIndex);
 228                     localpart = rawname.substring(colonIndex+1);
 229                 }
 230                 String uri = schemaDoc.fNamespaceSupport.getURI(fSymbolTable.addSymbol(prefix));
 231                 localStrBuffer.append(rawname)
 232                 .append("=\"");
 233                 String value = annotationLocalAttrs.get(i++);
 234                 // search for pesky "s and <s within attr value:
 235                 value = processAttValue(value);
 236                 localStrBuffer.append(value)
 237                 .append("\" ");
 238             }
 239             // and now splice it into place; immediately after the annotation token, for simplicity's sake
 240             StringBuilder contentBuffer = new StringBuilder(contents.length() + localStrBuffer.length());
 241             int annotationTokenEnd = contents.indexOf(SchemaSymbols.ELT_ANNOTATION);
 242             // annotation must occur somewhere or we're in big trouble...
 243             if(annotationTokenEnd == -1) return null;
 244             annotationTokenEnd += SchemaSymbols.ELT_ANNOTATION.length();
 245             contentBuffer.append(contents.substring(0,annotationTokenEnd));
 246             contentBuffer.append(localStrBuffer.toString());
 247             contentBuffer.append(contents.substring(annotationTokenEnd, contents.length()));
 248             final String annotation = contentBuffer.toString();
 249             if (fValidateAnnotations) {
 250                 schemaDoc.addAnnotation(new XSAnnotationInfo(annotation, annotationParent));
 251             }
 252             return new XSAnnotationImpl(annotation, grammar);
 253         } else {
 254             if (fValidateAnnotations) {
 255                 schemaDoc.addAnnotation(new XSAnnotationInfo(contents, annotationParent));
 256             }
 257             return new XSAnnotationImpl(contents, grammar);
 258         }
 259     }
 260 
 261     // the QName simple type used to resolve qnames
 262     private static final XSSimpleType fQNameDV = (XSSimpleType)SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(SchemaSymbols.ATTVAL_QNAME);
 263     // Temp data structures to be re-used in traversing facets
 264     private StringBuilder fPattern = new StringBuilder();
 265     private final XSFacets xsFacets = new XSFacets();
 266 
 267     static final class FacetInfo {
 268 
 269         final XSFacets facetdata;
 270         final Element nodeAfterFacets;
 271         final short fPresentFacets;
 272         final short fFixedFacets;
 273 
 274         FacetInfo(XSFacets facets, Element nodeAfterFacets, short presentFacets, short fixedFacets) {
 275             facetdata = facets;
 276             this.nodeAfterFacets = nodeAfterFacets;
 277             fPresentFacets = presentFacets;
 278             fFixedFacets = fixedFacets;
 279         }
 280     }
 281 
 282     FacetInfo traverseFacets(Element content,
 283             XSSimpleType baseValidator,
 284             XSDocumentInfo schemaDoc) {
 285 
 286         short facetsPresent = 0 ;
 287         short facetsFixed = 0; // facets that have fixed="true"
 288         String facet;
 289         boolean hasQName = containsQName(baseValidator);
 290         List<String> enumData = null;
 291         XSObjectListImpl enumAnnotations = null;
 292         XSObjectListImpl patternAnnotations = null;
 293         List<NamespaceContext> enumNSDecls = hasQName ? new ArrayList<>() : null;
 294         int currentFacet = 0;
 295         xsFacets.reset();
 296         while (content != null) {
 297             // General Attribute Checking
 298             Object[] attrs = null;
 299             facet = DOMUtil.getLocalName(content);
 300             if (facet.equals(SchemaSymbols.ELT_ENUMERATION)) {
 301                 attrs = fAttrChecker.checkAttributes(content, false, schemaDoc, hasQName);
 302                 String enumVal = (String)attrs[XSAttributeChecker.ATTIDX_VALUE];
 303                 // The facet can't be used if the value is missing. Ignore
 304                 // this facet element.
 305                 if (enumVal == null) {
 306                     reportSchemaError("s4s-att-must-appear", new Object[]{SchemaSymbols.ELT_ENUMERATION, SchemaSymbols.ATT_VALUE}, content);
 307                     fAttrChecker.returnAttrArray (attrs, schemaDoc);
 308                     content = DOMUtil.getNextSiblingElement(content);
 309                     continue;
 310                 }
 311 
 312                 NamespaceSupport nsDecls = (NamespaceSupport)attrs[XSAttributeChecker.ATTIDX_ENUMNSDECLS];
 313 
 314                 // for NOTATION types, need to check whether there is a notation
 315                 // declared with the same name as the enumeration value.
 316                 if (baseValidator.getVariety() == XSSimpleType.VARIETY_ATOMIC &&
 317                         baseValidator.getPrimitiveKind() == XSSimpleType.PRIMITIVE_NOTATION) {
 318                     // need to use the namespace context returned from checkAttributes
 319                     schemaDoc.fValidationContext.setNamespaceSupport(nsDecls);
 320                     Object notation = null;
 321                     try{
 322                         QName temp = (QName)fQNameDV.validate(enumVal, schemaDoc.fValidationContext, null);
 323                         // try to get the notation decl. if failed, getGlobalDecl
 324                         // reports an error, so we don't need to report one again.
 325                         notation = fSchemaHandler.getGlobalDecl(schemaDoc, XSDHandler.NOTATION_TYPE, temp, content);
 326                     }catch(InvalidDatatypeValueException ex){
 327                         reportSchemaError(ex.getKey(), ex.getArgs(), content);
 328                     }
 329                     if (notation == null) {
 330                         // Either the QName value is invalid, or it doens't
 331                         // resolve to a notation declaration.
 332                         // Ignore this facet, to avoid instance validation problems
 333                         fAttrChecker.returnAttrArray (attrs, schemaDoc);
 334                         content = DOMUtil.getNextSiblingElement(content);
 335                         continue;
 336                     }
 337                     // restore to the normal namespace context
 338                     schemaDoc.fValidationContext.setNamespaceSupport(schemaDoc.fNamespaceSupport);
 339                 }
 340                 if (enumData == null){
 341                     enumData = new ArrayList<>();
 342                     enumAnnotations = new XSObjectListImpl();
 343                 }
 344                 enumData.add(enumVal);
 345                 enumAnnotations.addXSObject(null);
 346                 if (hasQName)
 347                     enumNSDecls.add(nsDecls);
 348                 Element child = DOMUtil.getFirstChildElement( content );
 349 
 350                 if (child != null &&
 351                     DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) {
 352                     // traverse annotation if any
 353                     enumAnnotations.addXSObject(enumAnnotations.getLength()-1,traverseAnnotationDecl(child, attrs, false, schemaDoc));
 354                     child = DOMUtil.getNextSiblingElement(child);
 355                 }
 356                 else {
 357                     String text = DOMUtil.getSyntheticAnnotation(content);
 358                     if (text != null) {
 359                         enumAnnotations.addXSObject(enumAnnotations.getLength()-1, traverseSyntheticAnnotation(content, text, attrs, false, schemaDoc));
 360                     }
 361                 }
 362                 if (child !=null) {
 363                     reportSchemaError("s4s-elt-must-match.1", new Object[]{"enumeration", "(annotation?)", DOMUtil.getLocalName(child)}, child);
 364                 }
 365             }
 366             else if (facet.equals(SchemaSymbols.ELT_PATTERN)) {
 367                 facetsPresent |= XSSimpleType.FACET_PATTERN;
 368                 attrs = fAttrChecker.checkAttributes(content, false, schemaDoc);
 369                 String patternVal = (String)attrs[XSAttributeChecker.ATTIDX_VALUE];
 370                 // The facet can't be used if the value is missing. Ignore
 371                 // this facet element.
 372                 if (patternVal == null) {
 373                     reportSchemaError("s4s-att-must-appear", new Object[]{SchemaSymbols.ELT_PATTERN, SchemaSymbols.ATT_VALUE}, content);
 374                     fAttrChecker.returnAttrArray (attrs, schemaDoc);
 375                     content = DOMUtil.getNextSiblingElement(content);
 376                     continue;
 377                 }
 378 
 379                 if (fPattern.length() == 0) {
 380                     fPattern.append(patternVal);
 381                 } else {
 382                     // ---------------------------------------------
 383                     //datatypes: 5.2.4 pattern: src-multiple-pattern
 384                     // ---------------------------------------------
 385                     fPattern.append("|");
 386                     fPattern.append(patternVal);
 387                 }
 388                 Element child = DOMUtil.getFirstChildElement( content );
 389                 if (child != null &&
 390                         DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) {
 391                     // traverse annotation if any
 392                     if (patternAnnotations == null){
 393                         patternAnnotations = new XSObjectListImpl();
 394                     }
 395                     patternAnnotations.addXSObject(traverseAnnotationDecl(child, attrs, false, schemaDoc));
 396                     child = DOMUtil.getNextSiblingElement(child);
 397                 }
 398                 else {
 399                     String text = DOMUtil.getSyntheticAnnotation(content);
 400                     if (text != null) {
 401                         if (patternAnnotations == null){
 402                             patternAnnotations = new XSObjectListImpl();
 403                         }
 404                         patternAnnotations.addXSObject(traverseSyntheticAnnotation(content, text, attrs, false, schemaDoc));
 405                     }
 406                 }
 407                 if (child !=null) {
 408                     reportSchemaError("s4s-elt-must-match.1", new Object[]{"pattern", "(annotation?)", DOMUtil.getLocalName(child)}, child);
 409                 }
 410             }
 411             else {
 412                 if (facet.equals(SchemaSymbols.ELT_MINLENGTH)) {
 413                     currentFacet = XSSimpleType.FACET_MINLENGTH;
 414                 }
 415                 else if (facet.equals(SchemaSymbols.ELT_MAXLENGTH)) {
 416                     currentFacet = XSSimpleType.FACET_MAXLENGTH;
 417                 }
 418                 else if (facet.equals(SchemaSymbols.ELT_MAXEXCLUSIVE)) {
 419                     currentFacet = XSSimpleType.FACET_MAXEXCLUSIVE;
 420                 }
 421                 else if (facet.equals(SchemaSymbols.ELT_MAXINCLUSIVE)) {
 422                     currentFacet = XSSimpleType.FACET_MAXINCLUSIVE;
 423                 }
 424                 else if (facet.equals(SchemaSymbols.ELT_MINEXCLUSIVE)) {
 425                     currentFacet = XSSimpleType.FACET_MINEXCLUSIVE;
 426                 }
 427                 else if (facet.equals(SchemaSymbols.ELT_MININCLUSIVE)) {
 428                     currentFacet = XSSimpleType.FACET_MININCLUSIVE;
 429                 }
 430                 else if (facet.equals(SchemaSymbols.ELT_TOTALDIGITS)) {
 431                     currentFacet = XSSimpleType.FACET_TOTALDIGITS;
 432                 }
 433                 else if (facet.equals(SchemaSymbols.ELT_FRACTIONDIGITS)) {
 434                     currentFacet = XSSimpleType.FACET_FRACTIONDIGITS;
 435                 }
 436                 else if (facet.equals(SchemaSymbols.ELT_WHITESPACE)) {
 437                     currentFacet = XSSimpleType.FACET_WHITESPACE;
 438                 }
 439                 else if (facet.equals(SchemaSymbols.ELT_LENGTH)) {
 440                     currentFacet = XSSimpleType.FACET_LENGTH;
 441                 }
 442                 else {
 443                     break;   // a non-facet
 444                 }
 445 
 446                 attrs = fAttrChecker.checkAttributes(content, false, schemaDoc);
 447 
 448                 // check for duplicate facets
 449                 if ((facetsPresent & currentFacet) != 0) {
 450                     // Ignore this facet, to avoid corrupting the previous facet
 451                     reportSchemaError("src-single-facet-value", new Object[]{facet}, content);
 452                     fAttrChecker.returnAttrArray (attrs, schemaDoc);
 453                     content = DOMUtil.getNextSiblingElement(content);
 454                     continue;
 455                 }
 456 
 457                 // The facet can't be used if the value is missing. Ignore
 458                 // this facet element.
 459                 if (attrs[XSAttributeChecker.ATTIDX_VALUE] == null) {
 460                     // Report an error if the "value" attribute is missing.
 461                     // If it's not missing, then its value is invalid, and an
 462                     // error should have already been reported by the
 463                     // attribute checker.
 464                     if (content.getAttributeNodeNS(null, "value") == null) {
 465                         reportSchemaError("s4s-att-must-appear", new Object[]{content.getLocalName(), SchemaSymbols.ATT_VALUE}, content);
 466                     }
 467                     fAttrChecker.returnAttrArray (attrs, schemaDoc);
 468                     content = DOMUtil.getNextSiblingElement(content);
 469                     continue;
 470                 }
 471 
 472                 facetsPresent |= currentFacet;
 473                 // check for fixed facet
 474                 if (((Boolean)attrs[XSAttributeChecker.ATTIDX_FIXED]).booleanValue()) {
 475                     facetsFixed |= currentFacet;
 476                 }
 477                 switch (currentFacet) {
 478                 case XSSimpleType.FACET_MINLENGTH:
 479                     xsFacets.minLength = ((XInt)attrs[XSAttributeChecker.ATTIDX_VALUE]).intValue();
 480                     break;
 481                 case XSSimpleType.FACET_MAXLENGTH:
 482                     xsFacets.maxLength = ((XInt)attrs[XSAttributeChecker.ATTIDX_VALUE]).intValue();
 483                     break;
 484                 case XSSimpleType.FACET_MAXEXCLUSIVE:
 485                     xsFacets.maxExclusive = (String)attrs[XSAttributeChecker.ATTIDX_VALUE];
 486                     break;
 487                 case XSSimpleType.FACET_MAXINCLUSIVE:
 488                     xsFacets.maxInclusive = (String)attrs[XSAttributeChecker.ATTIDX_VALUE];
 489                     break;
 490                 case XSSimpleType.FACET_MINEXCLUSIVE:
 491                     xsFacets.minExclusive = (String)attrs[XSAttributeChecker.ATTIDX_VALUE];
 492                     break;
 493                 case XSSimpleType.FACET_MININCLUSIVE:
 494                     xsFacets.minInclusive = (String)attrs[XSAttributeChecker.ATTIDX_VALUE];
 495                     break;
 496                 case XSSimpleType.FACET_TOTALDIGITS:
 497                     xsFacets.totalDigits = ((XInt)attrs[XSAttributeChecker.ATTIDX_VALUE]).intValue();
 498                     break;
 499                 case XSSimpleType.FACET_FRACTIONDIGITS:
 500                     xsFacets.fractionDigits = ((XInt)attrs[XSAttributeChecker.ATTIDX_VALUE]).intValue();
 501                     break;
 502                 case XSSimpleType.FACET_WHITESPACE:
 503                     xsFacets.whiteSpace = ((XInt)attrs[XSAttributeChecker.ATTIDX_VALUE]).shortValue();
 504                     break;
 505                 case XSSimpleType.FACET_LENGTH:
 506                     xsFacets.length = ((XInt)attrs[XSAttributeChecker.ATTIDX_VALUE]).intValue();
 507                     break;
 508                 }
 509 
 510                 Element child = DOMUtil.getFirstChildElement( content );
 511                 XSAnnotationImpl annotation = null;
 512                 if (child != null &&
 513                     DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) {
 514                     // traverse annotation if any
 515                     annotation = traverseAnnotationDecl(child, attrs, false, schemaDoc);
 516                     child = DOMUtil.getNextSiblingElement(child);
 517                 }
 518                 else {
 519                     String text = DOMUtil.getSyntheticAnnotation(content);
 520                     if (text != null) {
 521                         annotation = traverseSyntheticAnnotation(content, text, attrs, false, schemaDoc);
 522                     }
 523                }
 524                 switch (currentFacet) {
 525                 case XSSimpleType.FACET_MINLENGTH:
 526                     xsFacets.minLengthAnnotation = annotation;
 527                 break;
 528                 case XSSimpleType.FACET_MAXLENGTH:
 529                     xsFacets.maxLengthAnnotation = annotation;
 530                 break;
 531                 case XSSimpleType.FACET_MAXEXCLUSIVE:
 532                     xsFacets.maxExclusiveAnnotation = annotation;
 533                 break;
 534                 case XSSimpleType.FACET_MAXINCLUSIVE:
 535                     xsFacets.maxInclusiveAnnotation = annotation;
 536                 break;
 537                 case XSSimpleType.FACET_MINEXCLUSIVE:
 538                     xsFacets.minExclusiveAnnotation = annotation;
 539                 break;
 540                 case XSSimpleType.FACET_MININCLUSIVE:
 541                     xsFacets.minInclusiveAnnotation = annotation;
 542                 break;
 543                 case XSSimpleType.FACET_TOTALDIGITS:
 544                     xsFacets.totalDigitsAnnotation = annotation;
 545                 break;
 546                 case XSSimpleType.FACET_FRACTIONDIGITS:
 547                     xsFacets.fractionDigitsAnnotation = annotation;
 548                 break;
 549                 case XSSimpleType.FACET_WHITESPACE:
 550                     xsFacets.whiteSpaceAnnotation = annotation;
 551                 break;
 552                 case XSSimpleType.FACET_LENGTH:
 553                     xsFacets.lengthAnnotation = annotation;
 554                 break;
 555                 }
 556                 if (child != null) {
 557                     reportSchemaError("s4s-elt-must-match.1", new Object[]{facet, "(annotation?)", DOMUtil.getLocalName(child)}, child);
 558                 }
 559             }
 560             fAttrChecker.returnAttrArray (attrs, schemaDoc);
 561             content = DOMUtil.getNextSiblingElement(content);
 562         }
 563         if (enumData !=null) {
 564             facetsPresent |= XSSimpleType.FACET_ENUMERATION;
 565             xsFacets.enumeration = enumData;
 566             xsFacets.enumNSDecls = enumNSDecls;
 567             xsFacets.enumAnnotations = enumAnnotations;
 568         }
 569         if ((facetsPresent & XSSimpleType.FACET_PATTERN) != 0) {
 570             xsFacets.pattern = fPattern.toString();
 571             xsFacets.patternAnnotations = patternAnnotations;
 572         }
 573 
 574         fPattern.setLength(0);
 575 
 576         return new FacetInfo(xsFacets, content, facetsPresent, facetsFixed);
 577     }
 578 
 579 
 580     // return whether QName/NOTATION is part of the given type
 581     private boolean containsQName(XSSimpleType type) {
 582         if (type.getVariety() == XSSimpleType.VARIETY_ATOMIC) {
 583             short primitive = type.getPrimitiveKind();
 584             return (primitive == XSSimpleType.PRIMITIVE_QNAME ||
 585                     primitive == XSSimpleType.PRIMITIVE_NOTATION);
 586         }
 587         else if (type.getVariety() == XSSimpleType.VARIETY_LIST) {
 588             return containsQName((XSSimpleType)type.getItemType());
 589         }
 590         else if (type.getVariety() == XSSimpleType.VARIETY_UNION) {
 591             XSObjectList members = type.getMemberTypes();
 592             for (int i = 0; i < members.getLength(); i++) {
 593                 if (containsQName((XSSimpleType)members.item(i)))
 594                     return true;
 595             }
 596         }
 597         return false;
 598     }
 599 
 600     //
 601     // Traverse a set of attribute and attribute group elements
 602     // Needed by complexType and attributeGroup traversal
 603     // This method will return the first non-attribute/attrgrp found
 604     //
 605     Element traverseAttrsAndAttrGrps(Element firstAttr, XSAttributeGroupDecl attrGrp,
 606             XSDocumentInfo schemaDoc, SchemaGrammar grammar,
 607             XSComplexTypeDecl enclosingCT) {
 608 
 609         Element child=null;
 610         XSAttributeGroupDecl tempAttrGrp = null;
 611         XSAttributeUseImpl tempAttrUse = null;
 612         XSAttributeUse otherUse = null;
 613         String childName;
 614 
 615         for (child=firstAttr; child!=null; child=DOMUtil.getNextSiblingElement(child)) {
 616             childName = DOMUtil.getLocalName(child);
 617             if (childName.equals(SchemaSymbols.ELT_ATTRIBUTE)) {
 618                 tempAttrUse = fSchemaHandler.fAttributeTraverser.traverseLocal(child,
 619                         schemaDoc,
 620                         grammar,
 621                         enclosingCT);
 622                 if (tempAttrUse == null) continue;
 623                 if (tempAttrUse.fUse == SchemaSymbols.USE_PROHIBITED) {
 624                     attrGrp.addAttributeUse(tempAttrUse);
 625                     continue;
 626                 }
 627                 otherUse = attrGrp.getAttributeUseNoProhibited(
 628                         tempAttrUse.fAttrDecl.getNamespace(),
 629                         tempAttrUse.fAttrDecl.getName());
 630                 if (otherUse==null) {
 631                     String idName = attrGrp.addAttributeUse(tempAttrUse);
 632                     if (idName != null) {
 633                         String code = (enclosingCT == null) ? "ag-props-correct.3" : "ct-props-correct.5";
 634                         String name = (enclosingCT == null) ? attrGrp.fName : enclosingCT.getName();
 635                         reportSchemaError(code, new Object[]{name, tempAttrUse.fAttrDecl.getName(), idName}, child);
 636                     }
 637                 }
 638                 else if (otherUse != tempAttrUse) {
 639                     String code = (enclosingCT == null) ? "ag-props-correct.2" : "ct-props-correct.4";
 640                     String name = (enclosingCT == null) ? attrGrp.fName : enclosingCT.getName();
 641                     reportSchemaError(code, new Object[]{name, tempAttrUse.fAttrDecl.getName()}, child);
 642                 }
 643             }
 644             else if (childName.equals(SchemaSymbols.ELT_ATTRIBUTEGROUP)) {
 645                 //REVISIT: do we need to save some state at this point??
 646                 tempAttrGrp = fSchemaHandler.fAttributeGroupTraverser.traverseLocal(
 647                         child, schemaDoc, grammar);
 648                 if(tempAttrGrp == null ) continue;
 649                 XSObjectList attrUseS = tempAttrGrp.getAttributeUses();
 650                 XSAttributeUseImpl oneAttrUse;
 651                 int attrCount = attrUseS.getLength();
 652                 for (int i=0; i<attrCount; i++) {
 653                     oneAttrUse = (XSAttributeUseImpl)attrUseS.item(i);
 654                     if (oneAttrUse.fUse == SchemaSymbols.USE_PROHIBITED) {
 655                         attrGrp.addAttributeUse(oneAttrUse);
 656                         continue;
 657                     }
 658                     otherUse = attrGrp.getAttributeUseNoProhibited(
 659                             oneAttrUse.fAttrDecl.getNamespace(),
 660                             oneAttrUse.fAttrDecl.getName());
 661                     if (otherUse==null) {
 662                         String idName = attrGrp.addAttributeUse(oneAttrUse);
 663                         if (idName != null) {
 664                             String code = (enclosingCT == null) ? "ag-props-correct.3" : "ct-props-correct.5";
 665                             String name = (enclosingCT == null) ? attrGrp.fName : enclosingCT.getName();
 666                             reportSchemaError(code, new Object[]{name, oneAttrUse.fAttrDecl.getName(), idName}, child);
 667                         }
 668                     }
 669                     else if (oneAttrUse != otherUse) {
 670                         String code = (enclosingCT == null) ? "ag-props-correct.2" : "ct-props-correct.4";
 671                         String name = (enclosingCT == null) ? attrGrp.fName : enclosingCT.getName();
 672                         reportSchemaError(code, new Object[]{name, oneAttrUse.fAttrDecl.getName()}, child);
 673                     }
 674                 }
 675 
 676                 if (tempAttrGrp.fAttributeWC != null) {
 677                     if (attrGrp.fAttributeWC == null) {
 678                         attrGrp.fAttributeWC = tempAttrGrp.fAttributeWC;
 679                     }
 680                     // perform intersection of attribute wildcard
 681                     else {
 682                         attrGrp.fAttributeWC = attrGrp.fAttributeWC.
 683                         performIntersectionWith(tempAttrGrp.fAttributeWC, attrGrp.fAttributeWC.fProcessContents);
 684                         if (attrGrp.fAttributeWC == null) {
 685                             String code = (enclosingCT == null) ? "src-attribute_group.2" : "src-ct.4";
 686                             String name = (enclosingCT == null) ? attrGrp.fName : enclosingCT.getName();
 687                             reportSchemaError(code, new Object[]{name}, child);
 688                         }
 689                     }
 690                 }
 691             }
 692             else
 693                 break;
 694         } // for
 695 
 696         if (child != null) {
 697             childName = DOMUtil.getLocalName(child);
 698             if (childName.equals(SchemaSymbols.ELT_ANYATTRIBUTE)) {
 699                 XSWildcardDecl tempAttrWC = fSchemaHandler.fWildCardTraverser.
 700                 traverseAnyAttribute(child, schemaDoc, grammar);
 701                 if (attrGrp.fAttributeWC == null) {
 702                     attrGrp.fAttributeWC = tempAttrWC;
 703                 }
 704                 // perform intersection of attribute wildcard
 705                 else {
 706                     attrGrp.fAttributeWC = tempAttrWC.
 707                     performIntersectionWith(attrGrp.fAttributeWC, tempAttrWC.fProcessContents);
 708                     if (attrGrp.fAttributeWC == null) {
 709                         String code = (enclosingCT == null) ? "src-attribute_group.2" : "src-ct.4";
 710                         String name = (enclosingCT == null) ? attrGrp.fName : enclosingCT.getName();
 711                         reportSchemaError(code, new Object[]{name}, child);
 712                     }
 713                 }
 714                 child = DOMUtil.getNextSiblingElement(child);
 715             }
 716         }
 717 
 718         // Success
 719         return child;
 720 
 721     }
 722 
 723     void reportSchemaError (String key, Object[] args, Element ele) {
 724         fSchemaHandler.reportSchemaError(key, args, ele);
 725     }
 726 
 727     /**
 728      * Element/Attribute traversers call this method to check whether
 729      * the type is NOTATION without enumeration facet
 730      */
 731     void checkNotationType(String refName, XSTypeDefinition typeDecl, Element elem) {
 732         if (typeDecl.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE &&
 733                 ((XSSimpleType)typeDecl).getVariety() == XSSimpleType.VARIETY_ATOMIC &&
 734                 ((XSSimpleType)typeDecl).getPrimitiveKind() == XSSimpleType.PRIMITIVE_NOTATION) {
 735             if ((((XSSimpleType)typeDecl).getDefinedFacets() & XSSimpleType.FACET_ENUMERATION) == 0) {
 736                 reportSchemaError("enumeration-required-notation", new Object[]{typeDecl.getName(), refName, DOMUtil.getLocalName(elem)}, elem);
 737             }
 738         }
 739     }
 740 
 741     // Checks constraints for minOccurs, maxOccurs
 742     protected XSParticleDecl checkOccurrences(XSParticleDecl particle,
 743             String particleName, Element parent,
 744             int allContextFlags,
 745             long defaultVals) {
 746 
 747         int min = particle.fMinOccurs;
 748         int max = particle.fMaxOccurs;
 749         boolean defaultMin = (defaultVals & (1 << XSAttributeChecker.ATTIDX_MINOCCURS)) != 0;
 750         boolean defaultMax = (defaultVals & (1 << XSAttributeChecker.ATTIDX_MAXOCCURS)) != 0;
 751 
 752         boolean processingAllEl = ((allContextFlags & PROCESSING_ALL_EL) != 0);
 753         boolean processingAllGP = ((allContextFlags & PROCESSING_ALL_GP) != 0);
 754         boolean groupRefWithAll = ((allContextFlags & GROUP_REF_WITH_ALL) != 0);
 755         boolean isGroupChild    = ((allContextFlags & CHILD_OF_GROUP) != 0);
 756 
 757         // Neither minOccurs nor maxOccurs may be specified
 758         // for the child of a model group definition.
 759         if (isGroupChild) {
 760             if (!defaultMin) {
 761                 Object[] args = new Object[]{particleName, "minOccurs"};
 762                 reportSchemaError("s4s-att-not-allowed", args, parent);
 763                 min = 1;
 764             }
 765             if (!defaultMax) {
 766                 Object[] args = new Object[]{particleName, "maxOccurs"};
 767                 reportSchemaError("s4s-att-not-allowed", args, parent);
 768                 max = 1;
 769             }
 770         }
 771 
 772         // If minOccurs=maxOccurs=0, no component is specified
 773         if (min == 0 && max== 0) {
 774             particle.fType = XSParticleDecl.PARTICLE_EMPTY;
 775             return null;
 776         }
 777 
 778         // For the elements referenced in an <all>, minOccurs attribute
 779         // must be zero or one, and maxOccurs attribute must be one.
 780         // For a complex type definition that contains an <all> or a
 781         // reference a <group> whose model group is an all model group,
 782         // minOccurs and maxOccurs must be one.
 783         if (processingAllEl) {
 784             if (max != 1) {
 785                 reportSchemaError("cos-all-limited.2", new Object[]{
 786                         (max == SchemaSymbols.OCCURRENCE_UNBOUNDED) ? SchemaSymbols.ATTVAL_UNBOUNDED : Integer.toString(max),
 787                         ((XSElementDecl)particle.fValue).getName()}, parent);
 788                 max = 1;
 789                 if (min > 1)
 790                     min = 1;
 791             }
 792         }
 793         else if (processingAllGP || groupRefWithAll) {
 794             if (max != 1) {
 795                 reportSchemaError("cos-all-limited.1.2", null, parent);
 796                 if (min > 1)
 797                     min = 1;
 798                 max = 1;
 799             }
 800         }
 801 
 802         particle.fMinOccurs = min;
 803         particle.fMaxOccurs = max;
 804 
 805         return particle;
 806     }
 807 
 808     private static String processAttValue(String original) {
 809         final int length = original.length();
 810         // normally, nothing will happen
 811         for (int i = 0; i < length; ++i) {
 812             char currChar = original.charAt(i);
 813             if (currChar == '"' || currChar == '<' || currChar == '&' ||
 814                     currChar == 0x09 || currChar == 0x0A || currChar == 0x0D) {
 815                 return escapeAttValue(original, i);
 816             }
 817         }
 818         return original;
 819     }
 820 
 821     // this is not terribly performant!
 822     private static String escapeAttValue(String original, int from) {
 823         int i;
 824         final int length = original.length();
 825         StringBuilder newVal = new StringBuilder(length);
 826         newVal.append(original.substring(0, from));
 827         for (i = from; i < length; ++i) {
 828             char currChar = original.charAt(i);
 829             if (currChar == '"') {
 830                 newVal.append("&quot;");
 831             }
 832             else if (currChar == '<') {
 833                 newVal.append("&lt;");
 834             }
 835             else if (currChar == '&') {
 836                 newVal.append("&amp;");
 837             }
 838             // Must escape 0x09, 0x0A and 0x0D if they appear in attribute
 839             // value so that they may be round-tripped. They would otherwise
 840             // be transformed to a 0x20 during attribute value normalization.
 841             else if (currChar == 0x09) {
 842                 newVal.append("&#x9;");
 843             }
 844             else if (currChar == 0x0A) {
 845                 newVal.append("&#xA;");
 846             }
 847             else if (currChar == 0x0D) {
 848                 newVal.append("&#xD;");
 849             }
 850             else {
 851                 newVal.append(currChar);
 852             }
 853         }
 854         return newVal.toString();
 855     }
 856 }