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;
  22 
  23 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter;
  24 import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeValueException;
  25 import com.sun.org.apache.xerces.internal.impl.dv.ValidatedInfo;
  26 import com.sun.org.apache.xerces.internal.impl.dv.ValidationContext;
  27 import com.sun.org.apache.xerces.internal.impl.dv.XSSimpleType;
  28 import com.sun.org.apache.xerces.internal.impl.xs.models.CMBuilder;
  29 import com.sun.org.apache.xerces.internal.impl.xs.models.XSCMValidator;
  30 import com.sun.org.apache.xerces.internal.impl.xs.util.SimpleLocator;
  31 import com.sun.org.apache.xerces.internal.impl.xs.util.XSObjectListImpl;
  32 import com.sun.org.apache.xerces.internal.util.SymbolHash;
  33 import com.sun.org.apache.xerces.internal.xs.XSConstants;
  34 import com.sun.org.apache.xerces.internal.xs.XSObjectList;
  35 import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
  36 import java.util.ArrayList;
  37 import java.util.Collections;
  38 import java.util.Comparator;
  39 import java.util.List;
  40 
  41 /**
  42  * Constaints shared by traversers and validator
  43  *
  44  * @xerces.internal
  45  *
  46  * @author Sandy Gao, IBM
  47  *
  48  * @LastModified: Nov 2017
  49  */
  50 public class XSConstraints {
  51 
  52     // IHR: Visited on 2006-11-17
  53     // Added a boolean return value to particleValidRestriction (it was a void function)
  54     // to help the checkRecurseLax to know when expansion has happened and no order is required
  55     // (IHR@xbrl.org) (Ignacio@Hernandez-Ros.com)
  56 
  57     static final int OCCURRENCE_UNKNOWN = SchemaSymbols.OCCURRENCE_UNBOUNDED-1;
  58     static final XSSimpleType STRING_TYPE =
  59             (XSSimpleType)SchemaGrammar.SG_SchemaNS.getGlobalTypeDecl(SchemaSymbols.ATTVAL_STRING);
  60 
  61     private static XSParticleDecl fEmptyParticle = null;
  62     public static XSParticleDecl getEmptySequence() {
  63         if (fEmptyParticle == null) {
  64             XSModelGroupImpl group = new XSModelGroupImpl();
  65             group.fCompositor = XSModelGroupImpl.MODELGROUP_SEQUENCE;
  66             group.fParticleCount = 0;
  67             group.fParticles = null;
  68             group.fAnnotations = XSObjectListImpl.EMPTY_LIST;
  69             XSParticleDecl particle = new XSParticleDecl();
  70             particle.fType = XSParticleDecl.PARTICLE_MODELGROUP;
  71             particle.fValue = group;
  72             particle.fAnnotations = XSObjectListImpl.EMPTY_LIST;
  73             fEmptyParticle = particle;
  74         }
  75         return fEmptyParticle;
  76     }
  77 
  78     private static final Comparator<XSParticleDecl> ELEMENT_PARTICLE_COMPARATOR =
  79             new Comparator<XSParticleDecl>() {
  80 
  81         public int compare(XSParticleDecl o1, XSParticleDecl o2) {
  82             XSParticleDecl pDecl1 = o1;
  83             XSParticleDecl pDecl2 = o2;
  84             XSElementDecl decl1 = (XSElementDecl) pDecl1.fValue;
  85             XSElementDecl decl2 = (XSElementDecl) pDecl2.fValue;
  86 
  87             String namespace1 = decl1.getNamespace();
  88             String namespace2 = decl2.getNamespace();
  89             String name1 = decl1.getName();
  90             String name2 = decl2.getName();
  91 
  92             boolean sameNamespace = (namespace1 == namespace2);
  93             int namespaceComparison = 0;
  94 
  95             if (!sameNamespace) {
  96                 if (namespace1 != null) {
  97                     if (namespace2 != null){
  98                         namespaceComparison = namespace1.compareTo(namespace2);
  99                     }
 100                     else {
 101                         namespaceComparison = 1;
 102                     }
 103                 }
 104                 else {
 105                     namespaceComparison = -1;
 106                 }
 107             }
 108             //This assumes that the names are never null.
 109             return namespaceComparison != 0 ? namespaceComparison : name1.compareTo(name2);
 110         }
 111     };
 112 
 113     /**
 114      * check whether derived is valid derived from base, given a subset
 115      * of {restriction, extension}.B
 116      */
 117     public static boolean checkTypeDerivationOk(XSTypeDefinition derived, XSTypeDefinition base, short block) {
 118         // if derived is anyType, then it's valid only if base is anyType too
 119         if (derived == SchemaGrammar.fAnyType)
 120             return derived == base;
 121         // if derived is anySimpleType, then it's valid only if the base
 122         // is ur-type
 123         if (derived == SchemaGrammar.fAnySimpleType) {
 124             return (base == SchemaGrammar.fAnyType ||
 125                     base == SchemaGrammar.fAnySimpleType);
 126         }
 127 
 128         // if derived is simple type
 129         if (derived.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
 130             // if base is complex type
 131             if (base.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
 132                 // if base is anyType, change base to anySimpleType,
 133                 // otherwise, not valid
 134                 if (base == SchemaGrammar.fAnyType)
 135                     base = SchemaGrammar.fAnySimpleType;
 136                 else
 137                     return false;
 138             }
 139             return checkSimpleDerivation((XSSimpleType)derived,
 140                     (XSSimpleType)base, block);
 141         }
 142         else {
 143             return checkComplexDerivation((XSComplexTypeDecl)derived, base, block);
 144         }
 145     }
 146 
 147     /**
 148      * check whether simple type derived is valid derived from base,
 149      * given a subset of {restriction, extension}.
 150      */
 151     public static boolean checkSimpleDerivationOk(XSSimpleType derived, XSTypeDefinition base, short block) {
 152         // if derived is anySimpleType, then it's valid only if the base
 153         // is ur-type
 154         if (derived == SchemaGrammar.fAnySimpleType) {
 155             return (base == SchemaGrammar.fAnyType ||
 156                     base == SchemaGrammar.fAnySimpleType);
 157         }
 158 
 159         // if base is complex type
 160         if (base.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
 161             // if base is anyType, change base to anySimpleType,
 162             // otherwise, not valid
 163             if (base == SchemaGrammar.fAnyType)
 164                 base = SchemaGrammar.fAnySimpleType;
 165             else
 166                 return false;
 167         }
 168         return checkSimpleDerivation(derived, (XSSimpleType)base, block);
 169     }
 170 
 171     /**
 172      * check whether complex type derived is valid derived from base,
 173      * given a subset of {restriction, extension}.
 174      */
 175     public static boolean checkComplexDerivationOk(XSComplexTypeDecl derived, XSTypeDefinition base, short block) {
 176         // if derived is anyType, then it's valid only if base is anyType too
 177         if (derived == SchemaGrammar.fAnyType)
 178             return derived == base;
 179         return checkComplexDerivation(derived, base, block);
 180     }
 181 
 182     /**
 183      * Note: this will be a private method, and it assumes that derived is not
 184      *       anySimpleType, and base is not anyType. Another method will be
 185      *       introduced for public use, which will call this method.
 186      */
 187     private static boolean checkSimpleDerivation(XSSimpleType derived, XSSimpleType base, short block) {
 188         // 1 They are the same type definition.
 189         if (derived == base)
 190             return true;
 191 
 192         // 2 All of the following must be true:
 193         // 2.1 restriction is not in the subset, or in the {final} of its own {base type definition};
 194         if ((block & XSConstants.DERIVATION_RESTRICTION) != 0 ||
 195                 (derived.getBaseType().getFinal() & XSConstants.DERIVATION_RESTRICTION) != 0) {
 196             return false;
 197         }
 198 
 199         // 2.2 One of the following must be true:
 200         // 2.2.1 D's base type definition is B.
 201         XSSimpleType directBase = (XSSimpleType)derived.getBaseType();
 202         if (directBase == base)
 203             return true;
 204 
 205         // 2.2.2 D's base type definition is not the simple ur-type definition and is validly derived from B given the subset, as defined by this constraint.
 206         if (directBase != SchemaGrammar.fAnySimpleType &&
 207                 checkSimpleDerivation(directBase, base, block)) {
 208             return true;
 209         }
 210 
 211         // 2.2.3 D's {variety} is list or union and B is the simple ur-type definition.
 212         if ((derived.getVariety() == XSSimpleType.VARIETY_LIST ||
 213                 derived.getVariety() == XSSimpleType.VARIETY_UNION) &&
 214                 base == SchemaGrammar.fAnySimpleType) {
 215             return true;
 216         }
 217 
 218         // 2.2.4 B's {variety} is union and D is validly derived from a type definition in B's {member type definitions} given the subset, as defined by this constraint.
 219         if (base.getVariety() == XSSimpleType.VARIETY_UNION) {
 220             XSObjectList subUnionMemberDV = base.getMemberTypes();
 221             int subUnionSize = subUnionMemberDV.getLength();
 222             for (int i=0; i<subUnionSize; i++) {
 223                 base = (XSSimpleType)subUnionMemberDV.item(i);
 224                 if (checkSimpleDerivation(derived, base, block))
 225                     return true;
 226             }
 227         }
 228 
 229         return false;
 230     }
 231 
 232     /**
 233      * Note: this will be a private method, and it assumes that derived is not
 234      *       anyType. Another method will be introduced for public use,
 235      *       which will call this method.
 236      */
 237     private static boolean checkComplexDerivation(XSComplexTypeDecl derived, XSTypeDefinition base, short block) {
 238         // 2.1 B and D must be the same type definition.
 239         if (derived == base)
 240             return true;
 241 
 242         // 1 If B and D are not the same type definition, then the {derivation method} of D must not be in the subset.
 243         if ((derived.fDerivedBy & block) != 0)
 244             return false;
 245 
 246         // 2 One of the following must be true:
 247         XSTypeDefinition directBase = derived.fBaseType;
 248         // 2.2 B must be D's {base type definition}.
 249         if (directBase == base)
 250             return true;
 251 
 252         // 2.3 All of the following must be true:
 253         // 2.3.1 D's {base type definition} must not be the ur-type definition.
 254         if (directBase == SchemaGrammar.fAnyType ||
 255                 directBase == SchemaGrammar.fAnySimpleType) {
 256             return false;
 257         }
 258 
 259         // 2.3.2 The appropriate case among the following must be true:
 260         // 2.3.2.1 If D's {base type definition} is complex, then it must be validly derived from B given the subset as defined by this constraint.
 261         if (directBase.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
 262             return checkComplexDerivation((XSComplexTypeDecl)directBase, base, block);
 263 
 264         // 2.3.2.2 If D's {base type definition} is simple, then it must be validly derived from B given the subset as defined in Type Derivation OK (Simple) (3.14.6).
 265         if (directBase.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
 266             // if base is complex type
 267             if (base.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE) {
 268                 // if base is anyType, change base to anySimpleType,
 269                 // otherwise, not valid
 270                 if (base == SchemaGrammar.fAnyType)
 271                     base = SchemaGrammar.fAnySimpleType;
 272                 else
 273                     return false;
 274             }
 275             return checkSimpleDerivation((XSSimpleType)directBase,
 276                     (XSSimpleType)base, block);
 277         }
 278 
 279         return false;
 280     }
 281 
 282     /**
 283      * check whether a value is a valid default for some type
 284      * returns the compiled form of the value
 285      * The parameter value could be either a String or a ValidatedInfo object
 286      */
 287     public static Object ElementDefaultValidImmediate(XSTypeDefinition type, String value, ValidationContext context, ValidatedInfo vinfo) {
 288 
 289         XSSimpleType dv = null;
 290 
 291         // e-props-correct
 292         // For a string to be a valid default with respect to a type definition the appropriate case among the following must be true:
 293         // 1 If the type definition is a simple type definition, then the string must be valid with respect to that definition as defined by String Valid (3.14.4).
 294         if (type.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
 295             dv = (XSSimpleType)type;
 296         }
 297 
 298         // 2 If the type definition is a complex type definition, then all of the following must be true:
 299         else {
 300             // 2.1 its {content type} must be a simple type definition or mixed.
 301             XSComplexTypeDecl ctype = (XSComplexTypeDecl)type;
 302             // 2.2 The appropriate case among the following must be true:
 303             // 2.2.1 If the {content type} is a simple type definition, then the string must be valid with respect to that simple type definition as defined by String Valid (3.14.4).
 304             if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) {
 305                 dv = ctype.fXSSimpleType;
 306             }
 307             // 2.2.2 If the {content type} is mixed, then the {content type}'s particle must be emptiable as defined by Particle Emptiable (3.9.6).
 308             else if (ctype.fContentType == XSComplexTypeDecl.CONTENTTYPE_MIXED) {
 309                 if (!((XSParticleDecl)ctype.getParticle()).emptiable())
 310                     return null;
 311             }
 312             else {
 313                 return null;
 314             }
 315         }
 316 
 317         // get the simple type declaration, and validate
 318         Object actualValue = null;
 319         if (dv == null) {
 320             // complex type with mixed. to make sure that we store correct
 321             // information in vinfo and return the correct value, we use
 322             // "string" type for validation
 323             dv = STRING_TYPE;
 324         }
 325         try {
 326             // validate the original lexical rep, and set the actual value
 327             actualValue = dv.validate(value, context, vinfo);
 328             // validate the canonical lexical rep
 329             if (vinfo != null)
 330                 actualValue = dv.validate(vinfo.stringValue(), context, vinfo);
 331         } catch (InvalidDatatypeValueException ide) {
 332             return null;
 333         }
 334 
 335         return actualValue;
 336     }
 337 
 338     static void reportSchemaError(XMLErrorReporter errorReporter,
 339             SimpleLocator loc,
 340             String key, Object[] args) {
 341         if (loc != null) {
 342             errorReporter.reportError(loc, XSMessageFormatter.SCHEMA_DOMAIN,
 343                     key, args, XMLErrorReporter.SEVERITY_ERROR);
 344         }
 345         else {
 346             errorReporter.reportError(XSMessageFormatter.SCHEMA_DOMAIN,
 347                     key, args, XMLErrorReporter.SEVERITY_ERROR);
 348         }
 349     }
 350 
 351     /**
 352      * used to check the 3 constraints against each complex type
 353      * (should be each model group):
 354      * Unique Particle Attribution, Particle Derivation (Restriction),
 355      * Element Declrations Consistent.
 356      */
 357     public static void fullSchemaChecking(XSGrammarBucket grammarBucket,
 358             SubstitutionGroupHandler SGHandler,
 359             CMBuilder cmBuilder,
 360             XMLErrorReporter errorReporter) {
 361         // get all grammars, and put all substitution group information
 362         // in the substitution group handler
 363         SchemaGrammar[] grammars = grammarBucket.getGrammars();
 364         for (int i = grammars.length-1; i >= 0; i--) {
 365             SGHandler.addSubstitutionGroup(grammars[i].getSubstitutionGroups());
 366         }
 367 
 368         XSParticleDecl fakeDerived = new XSParticleDecl();
 369         XSParticleDecl fakeBase = new XSParticleDecl();
 370         fakeDerived.fType = XSParticleDecl.PARTICLE_MODELGROUP;
 371         fakeBase.fType = XSParticleDecl.PARTICLE_MODELGROUP;
 372         // before worrying about complexTypes, let's get
 373         // groups redefined by restriction out of the way.
 374         for (int g = grammars.length-1; g >= 0; g--) {
 375             XSGroupDecl [] redefinedGroups = grammars[g].getRedefinedGroupDecls();
 376             SimpleLocator [] rgLocators = grammars[g].getRGLocators();
 377             for(int i=0; i<redefinedGroups.length; ) {
 378                 XSGroupDecl derivedGrp = redefinedGroups[i++];
 379                 XSModelGroupImpl derivedMG = derivedGrp.fModelGroup;
 380                 XSGroupDecl baseGrp = redefinedGroups[i++];
 381                 XSModelGroupImpl baseMG = baseGrp.fModelGroup;
 382                 fakeDerived.fValue = derivedMG;
 383                 fakeBase.fValue = baseMG;
 384                 if(baseMG == null) {
 385                     if(derivedMG != null) { // can't be a restriction!
 386                         reportSchemaError(errorReporter, rgLocators[i/2-1],
 387                                 "src-redefine.6.2.2",
 388                                 new Object[]{derivedGrp.fName, "rcase-Recurse.2"});
 389                     }
 390                 } else if (derivedMG == null) {
 391                     if (!fakeBase.emptiable()) {
 392                         reportSchemaError(errorReporter, rgLocators[i/2-1],
 393                                 "src-redefine.6.2.2",
 394                                 new Object[]{derivedGrp.fName, "rcase-Recurse.2"});
 395                     }
 396                 } else {
 397                     try {
 398                         particleValidRestriction(fakeDerived, SGHandler, fakeBase, SGHandler);
 399                     } catch (XMLSchemaException e) {
 400                         String key = e.getKey();
 401                         reportSchemaError(errorReporter, rgLocators[i/2-1],
 402                                 key,
 403                                 e.getArgs());
 404                         reportSchemaError(errorReporter, rgLocators[i/2-1],
 405                                 "src-redefine.6.2.2",
 406                                 new Object[]{derivedGrp.fName, key});
 407                     }
 408                 }
 409             }
 410         }
 411 
 412         // for each complex type, check the 3 constraints.
 413         // types need to be checked
 414         XSComplexTypeDecl[] types;
 415         SimpleLocator [] ctLocators;
 416         // to hold the errors
 417         // REVISIT: do we want to report all errors? or just one?
 418         //XMLSchemaError1D errors = new XMLSchemaError1D();
 419         // whether need to check this type again;
 420         // whether only do UPA checking
 421         boolean further, fullChecked;
 422         // if do all checkings, how many need to be checked again.
 423         int keepType;
 424         // i: grammar; j: type; k: error
 425         // for all grammars
 426         SymbolHash elemTable = new SymbolHash();
 427         for (int i = grammars.length-1, j; i >= 0; i--) {
 428             // get whether to skip EDC, and types need to be checked
 429             keepType = 0;
 430             fullChecked = grammars[i].fFullChecked;
 431             types = grammars[i].getUncheckedComplexTypeDecls();
 432             ctLocators = grammars[i].getUncheckedCTLocators();
 433             // for each type
 434             for (j = 0; j < types.length; j++) {
 435                 // if we've already full-checked this grammar, then
 436                 // skip the EDC constraint
 437                 if (!fullChecked) {
 438                     // 1. Element Decl Consistent
 439                     if (types[j].fParticle!=null) {
 440                         elemTable.clear();
 441                         try {
 442                             checkElementDeclsConsistent(types[j], types[j].fParticle,
 443                                     elemTable, SGHandler);
 444                         }
 445                         catch (XMLSchemaException e) {
 446                             reportSchemaError(errorReporter, ctLocators[j],
 447                                     e.getKey(),
 448                                     e.getArgs());
 449                         }
 450                     }
 451                 }
 452 
 453                 // 2. Particle Derivation
 454 
 455                 if (types[j].fBaseType != null &&
 456                         types[j].fBaseType != SchemaGrammar.fAnyType &&
 457                         types[j].fDerivedBy == XSConstants.DERIVATION_RESTRICTION &&
 458                         (types[j].fBaseType instanceof XSComplexTypeDecl)) {
 459 
 460                     XSParticleDecl derivedParticle=types[j].fParticle;
 461                     XSParticleDecl baseParticle=
 462                         ((XSComplexTypeDecl)(types[j].fBaseType)).fParticle;
 463                     if (derivedParticle==null) {
 464                         if (baseParticle!=null && !baseParticle.emptiable()) {
 465                             reportSchemaError(errorReporter,ctLocators[j],
 466                                     "derivation-ok-restriction.5.3.2",
 467                                     new Object[]{types[j].fName, types[j].fBaseType.getName()});
 468                         }
 469                     }
 470                     else if (baseParticle!=null) {
 471                         try {
 472                             particleValidRestriction(types[j].fParticle,
 473                                     SGHandler,
 474                                     ((XSComplexTypeDecl)(types[j].fBaseType)).fParticle,
 475                                     SGHandler);
 476                         } catch (XMLSchemaException e) {
 477                             reportSchemaError(errorReporter, ctLocators[j],
 478                                     e.getKey(),
 479                                     e.getArgs());
 480                             reportSchemaError(errorReporter, ctLocators[j],
 481                                     "derivation-ok-restriction.5.4.2",
 482                                     new Object[]{types[j].fName});
 483                         }
 484                     }
 485                     else {
 486                         reportSchemaError(errorReporter, ctLocators[j],
 487                                 "derivation-ok-restriction.5.4.2",
 488                                 new Object[]{types[j].fName});
 489                     }
 490                 }
 491                 // 3. UPA
 492                 // get the content model and check UPA
 493                 XSCMValidator cm = types[j].getContentModel(cmBuilder, true);
 494                 further = false;
 495                 if (cm != null) {
 496                     try {
 497                         further = cm.checkUniqueParticleAttribution(SGHandler);
 498                     } catch (XMLSchemaException e) {
 499                         reportSchemaError(errorReporter, ctLocators[j],
 500                                 e.getKey(),
 501                                 e.getArgs());
 502                     }
 503                 }
 504                 // now report all errors
 505                 // REVISIT: do we want to report all errors? or just one?
 506                 /*for (k = errors.getErrorCodeNum()-1; k >= 0; k--) {
 507                     reportSchemaError(errorReporter, ctLocators[j],
 508                                       errors.getErrorCode(k),
 509                                       errors.getArgs(k));
 510                 }*/
 511 
 512                 // if we are doing all checkings, and this one needs further
 513                 // checking, store it in the type array.
 514                 if (!fullChecked && further)
 515                     types[keepType++] = types[j];
 516 
 517                 // clear errors for the next type.
 518                 // REVISIT: do we want to report all errors? or just one?
 519                 //errors.clear();
 520             }
 521             // we've done with the types in this grammar. if we are checking
 522             // all constraints, need to trim type array to a proper size:
 523             // only contain those need further checking.
 524             // and mark this grammar that it only needs UPA checking.
 525             if (!fullChecked) {
 526                 grammars[i].setUncheckedTypeNum(keepType);
 527                 grammars[i].fFullChecked = true;
 528             }
 529         }
 530     }
 531 
 532     /*
 533        Check that a given particle is a valid restriction of a base particle.
 534      */
 535 
 536     public static void checkElementDeclsConsistent(XSComplexTypeDecl type,
 537             XSParticleDecl particle,
 538             SymbolHash elemDeclHash,
 539             SubstitutionGroupHandler sgHandler)
 540         throws XMLSchemaException {
 541 
 542         // check for elements in the tree with the same name and namespace
 543 
 544         int pType = particle.fType;
 545 
 546         if (pType == XSParticleDecl.PARTICLE_WILDCARD)
 547             return;
 548 
 549         if (pType == XSParticleDecl.PARTICLE_ELEMENT) {
 550             XSElementDecl elem = (XSElementDecl)(particle.fValue);
 551             findElemInTable(type, elem, elemDeclHash);
 552 
 553             if (elem.fScope == XSConstants.SCOPE_GLOBAL) {
 554                 // Check for subsitution groups.
 555                 XSElementDecl[] subGroup = sgHandler.getSubstitutionGroup(elem);
 556                 for (int i = 0; i < subGroup.length; i++) {
 557                     findElemInTable(type, subGroup[i], elemDeclHash);
 558                 }
 559             }
 560             return;
 561         }
 562 
 563         XSModelGroupImpl group = (XSModelGroupImpl)particle.fValue;
 564         for (int i = 0; i < group.fParticleCount; i++)
 565             checkElementDeclsConsistent(type, group.fParticles[i], elemDeclHash, sgHandler);
 566     }
 567 
 568     public static void findElemInTable(XSComplexTypeDecl type, XSElementDecl elem,
 569             SymbolHash elemDeclHash)
 570         throws XMLSchemaException {
 571 
 572         // How can we avoid this concat?  LM.
 573         String name = elem.fName + "," + elem.fTargetNamespace;
 574 
 575         XSElementDecl existingElem = null;
 576         if ((existingElem = (XSElementDecl)(elemDeclHash.get(name))) == null) {
 577             // just add it in
 578             elemDeclHash.put(name, elem);
 579         }
 580         else {
 581             // If this is the same check element, we're O.K.
 582             if (elem == existingElem)
 583                 return;
 584 
 585             if (elem.fType != existingElem.fType) {
 586                 // Types are not the same
 587                 throw new XMLSchemaException("cos-element-consistent",
 588                         new Object[] {type.fName, elem.fName});
 589 
 590             }
 591         }
 592     }
 593 
 594     // Check that a given particle is a valid restriction of a base particle.
 595     //
 596     // IHR: 2006/11/17
 597     // Returns a boolean indicating if there has been expansion of substitution group
 598     // in the bParticle.
 599     // With this information the checkRecurseLax function knows when is
 600     // to keep the order and when to ignore it.
 601     private static boolean particleValidRestriction(XSParticleDecl dParticle,
 602             SubstitutionGroupHandler dSGHandler,
 603             XSParticleDecl bParticle,
 604             SubstitutionGroupHandler bSGHandler)
 605         throws XMLSchemaException {
 606         return particleValidRestriction(dParticle, dSGHandler, bParticle, bSGHandler, true);
 607     }
 608 
 609     private static boolean particleValidRestriction(XSParticleDecl dParticle,
 610             SubstitutionGroupHandler dSGHandler,
 611             XSParticleDecl bParticle,
 612             SubstitutionGroupHandler bSGHandler,
 613             boolean checkWCOccurrence)
 614         throws XMLSchemaException {
 615 
 616         List<XSParticleDecl> dChildren = null;
 617         List<XSParticleDecl> bChildren = null;
 618         int dMinEffectiveTotalRange=OCCURRENCE_UNKNOWN;
 619         int dMaxEffectiveTotalRange=OCCURRENCE_UNKNOWN;
 620 
 621         // By default there has been no expansion
 622         boolean bExpansionHappened = false;
 623 
 624         // Check for empty particles.   If either base or derived particle is empty,
 625         // (and the other isn't) it's an error.
 626         if (dParticle.isEmpty() && !bParticle.emptiable()) {
 627             throw new XMLSchemaException("cos-particle-restrict.a", null);
 628         }
 629         else if (!dParticle.isEmpty() && bParticle.isEmpty()) {
 630             throw new XMLSchemaException("cos-particle-restrict.b", null);
 631         }
 632 
 633         //
 634         // Do setup prior to invoking the Particle (Restriction) cases.
 635         // This involves:
 636         //   - removing pointless occurrences for groups, and retrieving a vector of
 637         //     non-pointless children
 638         //   - turning top-level elements with substitution groups into CHOICE groups.
 639         //
 640 
 641         short dType = dParticle.fType;
 642         //
 643         // Handle pointless groups for the derived particle
 644         //
 645         if (dType == XSParticleDecl.PARTICLE_MODELGROUP) {
 646             dType = ((XSModelGroupImpl)dParticle.fValue).fCompositor;
 647 
 648             // Find a group, starting with this particle, with more than 1 child.   There
 649             // may be none, and the particle of interest trivially becomes an element or
 650             // wildcard.
 651             XSParticleDecl dtmp = getNonUnaryGroup(dParticle);
 652             if (dtmp != dParticle) {
 653                 // Particle has been replaced.   Retrieve new type info.
 654                 dParticle = dtmp;
 655                 dType = dParticle.fType;
 656                 if (dType == XSParticleDecl.PARTICLE_MODELGROUP)
 657                     dType = ((XSModelGroupImpl)dParticle.fValue).fCompositor;
 658             }
 659 
 660             // Fill in a vector with the children of the particle, removing any
 661             // pointless model groups in the process.
 662             dChildren = removePointlessChildren(dParticle);
 663         }
 664 
 665         int dMinOccurs = dParticle.fMinOccurs;
 666         int dMaxOccurs = dParticle.fMaxOccurs;
 667 
 668         //
 669         // For elements which are the heads of substitution groups, treat as CHOICE
 670         //
 671         if (dSGHandler != null && dType == XSParticleDecl.PARTICLE_ELEMENT) {
 672             XSElementDecl dElement = (XSElementDecl)dParticle.fValue;
 673 
 674             if (dElement.fScope == XSConstants.SCOPE_GLOBAL) {
 675                 // Check for subsitution groups.   Treat any element that has a
 676                 // subsitution group as a choice.   Fill in the children vector with the
 677                 // members of the substitution group
 678                 XSElementDecl[] subGroup = dSGHandler.getSubstitutionGroup(dElement);
 679                 if (subGroup.length >0 ) {
 680                     // Now, set the type to be CHOICE.  The "group" will have the same
 681                     // occurrence information as the original particle.
 682                     dType = XSModelGroupImpl.MODELGROUP_CHOICE;
 683                     dMinEffectiveTotalRange = dMinOccurs;
 684                     dMaxEffectiveTotalRange = dMaxOccurs;
 685 
 686                     // Fill in the vector of children
 687                     dChildren = new ArrayList<>(subGroup.length+1);
 688                     for (int i = 0; i < subGroup.length; i++) {
 689                         addElementToParticleVector(dChildren, subGroup[i]);
 690                     }
 691                     addElementToParticleVector(dChildren, dElement);
 692                     Collections.sort(dChildren, ELEMENT_PARTICLE_COMPARATOR);
 693 
 694                     // Set the handler to null, to indicate that we've finished handling
 695                     // substitution groups for this particle.
 696                     dSGHandler = null;
 697                 }
 698             }
 699         }
 700 
 701         short bType = bParticle.fType;
 702         //
 703         // Handle pointless groups for the base particle
 704         //
 705         if (bType == XSParticleDecl.PARTICLE_MODELGROUP) {
 706             bType = ((XSModelGroupImpl)bParticle.fValue).fCompositor;
 707 
 708             // Find a group, starting with this particle, with more than 1 child.   There
 709             // may be none, and the particle of interest trivially becomes an element or
 710             // wildcard.
 711             XSParticleDecl btmp = getNonUnaryGroup(bParticle);
 712             if (btmp != bParticle) {
 713                 // Particle has been replaced.   Retrieve new type info.
 714                 bParticle = btmp;
 715                 bType = bParticle.fType;
 716                 if (bType == XSParticleDecl.PARTICLE_MODELGROUP)
 717                     bType = ((XSModelGroupImpl)bParticle.fValue).fCompositor;
 718             }
 719 
 720             // Fill in a vector with the children of the particle, removing any
 721             // pointless model groups in the process.
 722             bChildren = removePointlessChildren(bParticle);
 723         }
 724 
 725         int bMinOccurs = bParticle.fMinOccurs;
 726         int bMaxOccurs = bParticle.fMaxOccurs;
 727 
 728         if (bSGHandler != null && bType == XSParticleDecl.PARTICLE_ELEMENT) {
 729             XSElementDecl bElement = (XSElementDecl)bParticle.fValue;
 730 
 731             if (bElement.fScope == XSConstants.SCOPE_GLOBAL) {
 732                 // Check for subsitution groups.   Treat any element that has a
 733                 // subsitution group as a choice.   Fill in the children vector with the
 734                 // members of the substitution group
 735                 XSElementDecl[] bsubGroup = bSGHandler.getSubstitutionGroup(bElement);
 736                 if (bsubGroup.length >0 ) {
 737                     // Now, set the type to be CHOICE
 738                     bType = XSModelGroupImpl.MODELGROUP_CHOICE;
 739 
 740                     bChildren = new ArrayList<>(bsubGroup.length+1);
 741                     for (int i = 0; i < bsubGroup.length; i++) {
 742                         addElementToParticleVector(bChildren, bsubGroup[i]);
 743                     }
 744                     addElementToParticleVector(bChildren, bElement);
 745                     Collections.sort(bChildren, ELEMENT_PARTICLE_COMPARATOR);
 746                     // Set the handler to null, to indicate that we've finished handling
 747                     // substitution groups for this particle.
 748                     bSGHandler = null;
 749 
 750                     // if we are here expansion of bParticle happened
 751                     bExpansionHappened = true;
 752                 }
 753             }
 754         }
 755 
 756         //
 757         // O.K. - Figure out which particle derivation rule applies and call it
 758         //
 759         switch (dType) {
 760             case XSParticleDecl.PARTICLE_ELEMENT:
 761             {
 762                 switch (bType) {
 763 
 764                     // Elt:Elt NameAndTypeOK
 765                     case XSParticleDecl.PARTICLE_ELEMENT:
 766                     {
 767                         checkNameAndTypeOK((XSElementDecl)dParticle.fValue,dMinOccurs,dMaxOccurs,
 768                                 (XSElementDecl)bParticle.fValue,bMinOccurs,bMaxOccurs);
 769                         return bExpansionHappened;
 770                     }
 771 
 772                     // Elt:Any NSCompat
 773                     case XSParticleDecl.PARTICLE_WILDCARD:
 774                     {
 775                         checkNSCompat((XSElementDecl)dParticle.fValue,dMinOccurs,dMaxOccurs,
 776                                 (XSWildcardDecl)bParticle.fValue,bMinOccurs,bMaxOccurs,
 777                                 checkWCOccurrence);
 778                         return bExpansionHappened;
 779                     }
 780 
 781                     // Elt:All RecurseAsIfGroup
 782                     case XSModelGroupImpl.MODELGROUP_CHOICE:
 783                     {
 784                         // Treat the element as if it were in a group of the same type
 785                         // as the base Particle
 786                         dChildren = new ArrayList<>();
 787                         dChildren.add(dParticle);
 788 
 789                         checkRecurseLax(dChildren, 1, 1, dSGHandler,
 790                                 bChildren, bMinOccurs, bMaxOccurs, bSGHandler);
 791                         return bExpansionHappened;
 792                     }
 793                     case XSModelGroupImpl.MODELGROUP_SEQUENCE:
 794                     case XSModelGroupImpl.MODELGROUP_ALL:
 795                     {
 796                         // Treat the element as if it were in a group of the same type
 797                         // as the base Particle
 798                         dChildren = new ArrayList<>();
 799                         dChildren.add(dParticle);
 800 
 801                         checkRecurse(dChildren, 1, 1, dSGHandler,
 802                                 bChildren, bMinOccurs, bMaxOccurs, bSGHandler);
 803                         return bExpansionHappened;
 804                     }
 805 
 806                     default:
 807                     {
 808                         throw new XMLSchemaException("Internal-Error",
 809                                 new Object[]{"in particleValidRestriction"});
 810                     }
 811                 }
 812             }
 813 
 814             case XSParticleDecl.PARTICLE_WILDCARD:
 815             {
 816                 switch (bType) {
 817 
 818                     // Any:Any NSSubset
 819                     case XSParticleDecl.PARTICLE_WILDCARD:
 820                     {
 821                         checkNSSubset((XSWildcardDecl)dParticle.fValue, dMinOccurs, dMaxOccurs,
 822                                 (XSWildcardDecl)bParticle.fValue, bMinOccurs, bMaxOccurs);
 823                         return bExpansionHappened;
 824                     }
 825 
 826                     case XSModelGroupImpl.MODELGROUP_CHOICE:
 827                     case XSModelGroupImpl.MODELGROUP_SEQUENCE:
 828                     case XSModelGroupImpl.MODELGROUP_ALL:
 829                     case XSParticleDecl.PARTICLE_ELEMENT:
 830                     {
 831                         throw new XMLSchemaException("cos-particle-restrict.2",
 832                                 new Object[]{"any:choice,sequence,all,elt"});
 833                     }
 834 
 835                     default:
 836                     {
 837                         throw new XMLSchemaException("Internal-Error",
 838                                 new Object[]{"in particleValidRestriction"});
 839                     }
 840                 }
 841             }
 842 
 843             case XSModelGroupImpl.MODELGROUP_ALL:
 844             {
 845                 switch (bType) {
 846 
 847                     // All:Any NSRecurseCheckCardinality
 848                     case XSParticleDecl.PARTICLE_WILDCARD:
 849                     {
 850                         if (dMinEffectiveTotalRange == OCCURRENCE_UNKNOWN)
 851                             dMinEffectiveTotalRange = dParticle.minEffectiveTotalRange();
 852                         if (dMaxEffectiveTotalRange == OCCURRENCE_UNKNOWN)
 853                             dMaxEffectiveTotalRange = dParticle.maxEffectiveTotalRange();
 854 
 855                         checkNSRecurseCheckCardinality(dChildren, dMinEffectiveTotalRange,
 856                                 dMaxEffectiveTotalRange,
 857                                 dSGHandler,
 858                                 bParticle,bMinOccurs,bMaxOccurs,
 859                                 checkWCOccurrence);
 860 
 861                         return bExpansionHappened;
 862                     }
 863 
 864                     case XSModelGroupImpl.MODELGROUP_ALL:
 865                     {
 866                         checkRecurse(dChildren, dMinOccurs, dMaxOccurs, dSGHandler,
 867                                 bChildren, bMinOccurs, bMaxOccurs, bSGHandler);
 868                         return bExpansionHappened;
 869                     }
 870 
 871                     case XSModelGroupImpl.MODELGROUP_CHOICE:
 872                     case XSModelGroupImpl.MODELGROUP_SEQUENCE:
 873                     case XSParticleDecl.PARTICLE_ELEMENT:
 874                     {
 875                         throw new XMLSchemaException("cos-particle-restrict.2",
 876                                 new Object[]{"all:choice,sequence,elt"});
 877                     }
 878 
 879                     default:
 880                     {
 881                         throw new XMLSchemaException("Internal-Error",
 882                                 new Object[]{"in particleValidRestriction"});
 883                     }
 884                 }
 885             }
 886 
 887             case XSModelGroupImpl.MODELGROUP_CHOICE:
 888             {
 889                 switch (bType) {
 890 
 891                     // Choice:Any NSRecurseCheckCardinality
 892                     case XSParticleDecl.PARTICLE_WILDCARD:
 893                     {
 894                         if (dMinEffectiveTotalRange == OCCURRENCE_UNKNOWN)
 895                             dMinEffectiveTotalRange = dParticle.minEffectiveTotalRange();
 896                         if (dMaxEffectiveTotalRange == OCCURRENCE_UNKNOWN)
 897                             dMaxEffectiveTotalRange = dParticle.maxEffectiveTotalRange();
 898 
 899                         checkNSRecurseCheckCardinality(dChildren, dMinEffectiveTotalRange,
 900                                 dMaxEffectiveTotalRange,
 901                                 dSGHandler,
 902                                 bParticle,bMinOccurs,bMaxOccurs,
 903                                 checkWCOccurrence);
 904                         return bExpansionHappened;
 905                     }
 906 
 907                     case XSModelGroupImpl.MODELGROUP_CHOICE:
 908                     {
 909                         checkRecurseLax(dChildren, dMinOccurs, dMaxOccurs, dSGHandler,
 910                                 bChildren, bMinOccurs, bMaxOccurs, bSGHandler);
 911                         return bExpansionHappened;
 912                     }
 913 
 914                     case XSModelGroupImpl.MODELGROUP_ALL:
 915                     case XSModelGroupImpl.MODELGROUP_SEQUENCE:
 916                     case XSParticleDecl.PARTICLE_ELEMENT:
 917                     {
 918                         throw new XMLSchemaException("cos-particle-restrict.2",
 919                                 new Object[]{"choice:all,sequence,elt"});
 920                     }
 921 
 922                     default:
 923                     {
 924                         throw new XMLSchemaException("Internal-Error",
 925                                 new Object[]{"in particleValidRestriction"});
 926                     }
 927                 }
 928             }
 929 
 930 
 931             case XSModelGroupImpl.MODELGROUP_SEQUENCE:
 932             {
 933                 switch (bType) {
 934 
 935                     // Choice:Any NSRecurseCheckCardinality
 936                     case XSParticleDecl.PARTICLE_WILDCARD:
 937                     {
 938                         if (dMinEffectiveTotalRange == OCCURRENCE_UNKNOWN)
 939                             dMinEffectiveTotalRange = dParticle.minEffectiveTotalRange();
 940                         if (dMaxEffectiveTotalRange == OCCURRENCE_UNKNOWN)
 941                             dMaxEffectiveTotalRange = dParticle.maxEffectiveTotalRange();
 942 
 943                         checkNSRecurseCheckCardinality(dChildren, dMinEffectiveTotalRange,
 944                                 dMaxEffectiveTotalRange,
 945                                 dSGHandler,
 946                                 bParticle,bMinOccurs,bMaxOccurs,
 947                                 checkWCOccurrence);
 948                         return bExpansionHappened;
 949                     }
 950 
 951                     case XSModelGroupImpl.MODELGROUP_ALL:
 952                     {
 953                         checkRecurseUnordered(dChildren, dMinOccurs, dMaxOccurs, dSGHandler,
 954                                 bChildren, bMinOccurs, bMaxOccurs, bSGHandler);
 955                         return bExpansionHappened;
 956                     }
 957 
 958                     case XSModelGroupImpl.MODELGROUP_SEQUENCE:
 959                     {
 960                         checkRecurse(dChildren, dMinOccurs, dMaxOccurs, dSGHandler,
 961                                 bChildren, bMinOccurs, bMaxOccurs, bSGHandler);
 962                         return bExpansionHappened;
 963                     }
 964 
 965                     case XSModelGroupImpl.MODELGROUP_CHOICE:
 966                     {
 967                         int min1 = dMinOccurs * dChildren.size();
 968                         int max1 = (dMaxOccurs == SchemaSymbols.OCCURRENCE_UNBOUNDED)?
 969                                 dMaxOccurs : dMaxOccurs * dChildren.size();
 970                         checkMapAndSum(dChildren, min1, max1, dSGHandler,
 971                                 bChildren, bMinOccurs, bMaxOccurs, bSGHandler);
 972                         return bExpansionHappened;
 973                     }
 974 
 975                     case XSParticleDecl.PARTICLE_ELEMENT:
 976                     {
 977                         throw new XMLSchemaException("cos-particle-restrict.2",
 978                                 new Object[]{"seq:elt"});
 979                     }
 980 
 981                     default:
 982                     {
 983                         throw new XMLSchemaException("Internal-Error",
 984                                 new Object[]{"in particleValidRestriction"});
 985                     }
 986                 }
 987             }
 988 
 989         }
 990 
 991         return bExpansionHappened;
 992     }
 993 
 994     private static void addElementToParticleVector (List<XSParticleDecl> v, XSElementDecl d)  {
 995 
 996         XSParticleDecl p = new XSParticleDecl();
 997         p.fValue = d;
 998         p.fType = XSParticleDecl.PARTICLE_ELEMENT;
 999         v.add(p);
1000 
1001     }
1002 
1003     private static XSParticleDecl getNonUnaryGroup(XSParticleDecl p) {
1004 
1005         if (p.fType == XSParticleDecl.PARTICLE_ELEMENT ||
1006                 p.fType == XSParticleDecl.PARTICLE_WILDCARD)
1007             return p;
1008 
1009         if (p.fMinOccurs==1 && p.fMaxOccurs==1 &&
1010                 p.fValue!=null && ((XSModelGroupImpl)p.fValue).fParticleCount == 1)
1011             return getNonUnaryGroup(((XSModelGroupImpl)p.fValue).fParticles[0]);
1012         else
1013             return p;
1014     }
1015 
1016     private static List<XSParticleDecl> removePointlessChildren(XSParticleDecl p)  {
1017 
1018         if (p.fType == XSParticleDecl.PARTICLE_ELEMENT ||
1019                 p.fType == XSParticleDecl.PARTICLE_WILDCARD)
1020             return null;
1021 
1022         List<XSParticleDecl> children = new ArrayList<>();
1023 
1024         XSModelGroupImpl group = (XSModelGroupImpl)p.fValue;
1025         for (int i = 0; i < group.fParticleCount; i++)
1026             gatherChildren(group.fCompositor, group.fParticles[i], children);
1027 
1028         return children;
1029     }
1030 
1031 
1032     private static void gatherChildren(int parentType, XSParticleDecl p, List<XSParticleDecl> children) {
1033 
1034         int min = p.fMinOccurs;
1035         int max = p.fMaxOccurs;
1036         int type = p.fType;
1037         if (type == XSParticleDecl.PARTICLE_MODELGROUP)
1038             type = ((XSModelGroupImpl)p.fValue).fCompositor;
1039 
1040         if (type == XSParticleDecl.PARTICLE_ELEMENT ||
1041                 type== XSParticleDecl.PARTICLE_WILDCARD) {
1042             children.add(p);
1043             return;
1044         }
1045 
1046         if (! (min==1 && max==1)) {
1047             children.add(p);
1048         }
1049         else if (parentType == type) {
1050             XSModelGroupImpl group = (XSModelGroupImpl)p.fValue;
1051             for (int i = 0; i < group.fParticleCount; i++)
1052                 gatherChildren(type, group.fParticles[i], children);
1053         }
1054         else if (!p.isEmpty()) {
1055             children.add(p);
1056         }
1057 
1058     }
1059 
1060     private static void checkNameAndTypeOK(XSElementDecl dElement, int dMin, int dMax,
1061             XSElementDecl bElement, int bMin, int bMax)
1062         throws XMLSchemaException {
1063 
1064 
1065         //
1066         // Check that the names are the same
1067         //
1068         if (dElement.fName != bElement.fName ||
1069                 dElement.fTargetNamespace != bElement.fTargetNamespace) {
1070             throw new XMLSchemaException(
1071                     "rcase-NameAndTypeOK.1",new Object[]{dElement.fName,
1072                             dElement.fTargetNamespace, bElement.fName, bElement.fTargetNamespace});
1073         }
1074 
1075         //
1076         // Check nillable
1077         //
1078         if (!bElement.getNillable() && dElement.getNillable()) {
1079             throw new XMLSchemaException("rcase-NameAndTypeOK.2",
1080                     new Object[]{dElement.fName});
1081         }
1082 
1083         //
1084         // Check occurrence range
1085         //
1086         if (!checkOccurrenceRange(dMin, dMax, bMin, bMax)) {
1087             throw new XMLSchemaException("rcase-NameAndTypeOK.3",
1088                     new Object[]{
1089                     dElement.fName,
1090                     Integer.toString(dMin),
1091                     dMax==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(dMax),
1092                             Integer.toString(bMin),
1093                             bMax==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(bMax)});
1094         }
1095 
1096         //
1097         // Check for consistent fixed values
1098         //
1099         if (bElement.getConstraintType() == XSConstants.VC_FIXED) {
1100             // derived one has to have a fixed value
1101             if (dElement.getConstraintType() != XSConstants.VC_FIXED) {
1102                 throw new XMLSchemaException("rcase-NameAndTypeOK.4.a",
1103                         new Object[]{dElement.fName, bElement.fDefault.stringValue()});
1104             }
1105 
1106             // get simple type
1107             boolean isSimple = false;
1108             if (dElement.fType.getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE ||
1109                     ((XSComplexTypeDecl)dElement.fType).fContentType == XSComplexTypeDecl.CONTENTTYPE_SIMPLE) {
1110                 isSimple = true;
1111             }
1112 
1113             // if there is no simple type, then compare based on string
1114             if (!isSimple && !bElement.fDefault.normalizedValue.equals(dElement.fDefault.normalizedValue) ||
1115                     isSimple && !bElement.fDefault.actualValue.equals(dElement.fDefault.actualValue)) {
1116                 throw new XMLSchemaException("rcase-NameAndTypeOK.4.b",
1117                         new Object[]{dElement.fName,
1118                         dElement.fDefault.stringValue(),
1119                         bElement.fDefault.stringValue()});
1120             }
1121         }
1122 
1123         //
1124         // Check identity constraints
1125         //
1126         checkIDConstraintRestriction(dElement, bElement);
1127 
1128         //
1129         // Check for disallowed substitutions
1130         //
1131         int blockSet1 = dElement.fBlock;
1132         int blockSet2 = bElement.fBlock;
1133         if (((blockSet1 & blockSet2)!=blockSet2) ||
1134                 (blockSet1==XSConstants.DERIVATION_NONE && blockSet2!=XSConstants.DERIVATION_NONE))
1135             throw new XMLSchemaException("rcase-NameAndTypeOK.6",
1136                     new Object[]{dElement.fName});
1137 
1138 
1139         //
1140         // Check that the derived element's type is derived from the base's.
1141         //
1142         if (!checkTypeDerivationOk(dElement.fType, bElement.fType,
1143                 (short)(XSConstants.DERIVATION_EXTENSION|XSConstants.DERIVATION_LIST|XSConstants.DERIVATION_UNION))) {
1144             throw new XMLSchemaException("rcase-NameAndTypeOK.7",
1145                     new Object[]{dElement.fName, dElement.fType.getName(), bElement.fType.getName()});
1146         }
1147 
1148     }
1149 
1150 
1151     private static void checkIDConstraintRestriction(XSElementDecl derivedElemDecl,
1152             XSElementDecl baseElemDecl)
1153         throws XMLSchemaException {
1154         // TODO
1155     } // checkIDConstraintRestriction
1156 
1157 
1158     private static boolean checkOccurrenceRange(int min1, int max1, int min2, int max2) {
1159 
1160         if ((min1 >= min2) &&
1161                 ((max2==SchemaSymbols.OCCURRENCE_UNBOUNDED) ||
1162                         (max1!=SchemaSymbols.OCCURRENCE_UNBOUNDED && max1<=max2)))
1163             return true;
1164         else
1165             return false;
1166     }
1167 
1168     private static void checkNSCompat(XSElementDecl elem, int min1, int max1,
1169             XSWildcardDecl wildcard, int min2, int max2,
1170             boolean checkWCOccurrence)
1171         throws XMLSchemaException {
1172 
1173         // check Occurrence ranges
1174         if (checkWCOccurrence && !checkOccurrenceRange(min1,max1,min2,max2)) {
1175             throw new XMLSchemaException("rcase-NSCompat.2",
1176                     new Object[]{
1177                     elem.fName,
1178                     Integer.toString(min1),
1179                     max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1),
1180                             Integer.toString(min2),
1181                             max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)});
1182         }
1183 
1184         // check wildcard allows namespace of element
1185         if (!wildcard.allowNamespace(elem.fTargetNamespace))  {
1186             throw new XMLSchemaException("rcase-NSCompat.1",
1187                     new Object[]{elem.fName,elem.fTargetNamespace});
1188         }
1189 
1190     }
1191 
1192     private static void checkNSSubset(XSWildcardDecl dWildcard, int min1, int max1,
1193             XSWildcardDecl bWildcard, int min2, int max2)
1194         throws XMLSchemaException {
1195 
1196         // check Occurrence ranges
1197         if (!checkOccurrenceRange(min1,max1,min2,max2)) {
1198             throw new XMLSchemaException("rcase-NSSubset.2", new Object[]{
1199                     Integer.toString(min1),
1200                     max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1),
1201                             Integer.toString(min2),
1202                             max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)});
1203         }
1204 
1205         // check wildcard subset
1206         if (!dWildcard.isSubsetOf(bWildcard)) {
1207             throw new XMLSchemaException("rcase-NSSubset.1", null);
1208         }
1209 
1210         if (dWildcard.weakerProcessContents(bWildcard)) {
1211             throw new XMLSchemaException("rcase-NSSubset.3",
1212                     new Object[]{dWildcard.getProcessContentsAsString(),
1213                     bWildcard.getProcessContentsAsString()});
1214         }
1215 
1216     }
1217 
1218 
1219     private static void checkNSRecurseCheckCardinality(List<XSParticleDecl> children, int min1, int max1,
1220             SubstitutionGroupHandler dSGHandler,
1221             XSParticleDecl wildcard, int min2, int max2,
1222             boolean checkWCOccurrence)
1223         throws XMLSchemaException {
1224 
1225 
1226         // check Occurrence ranges
1227         if (checkWCOccurrence && !checkOccurrenceRange(min1,max1,min2,max2)) {
1228             throw new XMLSchemaException("rcase-NSRecurseCheckCardinality.2", new Object[]{
1229                     Integer.toString(min1),
1230                     max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1),
1231                             Integer.toString(min2),
1232                             max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)});
1233         }
1234 
1235         // Check that each member of the group is a valid restriction of the wildcard
1236         int count = children.size();
1237         try {
1238             for (int i = 0; i < count; i++) {
1239                 XSParticleDecl particle1 = children.get(i);
1240                 particleValidRestriction(particle1, dSGHandler, wildcard, null, false);
1241 
1242             }
1243         }
1244         // REVISIT: should we really just ignore original cause of this error?
1245         //          how can we report it?
1246         catch (XMLSchemaException e) {
1247             throw new XMLSchemaException("rcase-NSRecurseCheckCardinality.1", null);
1248         }
1249 
1250     }
1251 
1252     private static void checkRecurse(List<XSParticleDecl> dChildren, int min1, int max1,
1253             SubstitutionGroupHandler dSGHandler,
1254             List<XSParticleDecl> bChildren, int min2, int max2,
1255             SubstitutionGroupHandler bSGHandler)
1256         throws XMLSchemaException {
1257 
1258         // check Occurrence ranges
1259         if (!checkOccurrenceRange(min1,max1,min2,max2)) {
1260             throw new XMLSchemaException("rcase-Recurse.1", new Object[]{
1261                     Integer.toString(min1),
1262                     max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1),
1263                     Integer.toString(min2),
1264                     max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)});
1265         }
1266 
1267         int count1= dChildren.size();
1268         int count2= bChildren.size();
1269 
1270         int current = 0;
1271         label: for (int i = 0; i<count1; i++) {
1272 
1273             XSParticleDecl particle1 = dChildren.get(i);
1274             for (int j = current; j<count2; j++) {
1275                 XSParticleDecl particle2 = bChildren.get(j);
1276                 current +=1;
1277                 try {
1278                     particleValidRestriction(particle1, dSGHandler, particle2, bSGHandler);
1279                     continue label;
1280                 }
1281                 catch (XMLSchemaException e) {
1282                     if (!particle2.emptiable())
1283                         throw new XMLSchemaException("rcase-Recurse.2", null);
1284                 }
1285             }
1286             throw new XMLSchemaException("rcase-Recurse.2", null);
1287         }
1288 
1289         // Now, see if there are some elements in the base we didn't match up
1290         for (int j=current; j < count2; j++) {
1291             XSParticleDecl particle2 = bChildren.get(j);
1292             if (!particle2.emptiable()) {
1293                 throw new XMLSchemaException("rcase-Recurse.2", null);
1294             }
1295         }
1296 
1297     }
1298 
1299     private static void checkRecurseUnordered(List<XSParticleDecl> dChildren, int min1, int max1,
1300             SubstitutionGroupHandler dSGHandler,
1301             List<XSParticleDecl> bChildren, int min2, int max2,
1302             SubstitutionGroupHandler bSGHandler)
1303         throws XMLSchemaException {
1304 
1305 
1306         // check Occurrence ranges
1307         if (!checkOccurrenceRange(min1,max1,min2,max2)) {
1308             throw new XMLSchemaException("rcase-RecurseUnordered.1", new Object[]{
1309                     Integer.toString(min1),
1310                     max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1),
1311                     Integer.toString(min2),
1312                     max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)});
1313         }
1314 
1315         int count1= dChildren.size();
1316         int count2 = bChildren.size();
1317 
1318         boolean foundIt[] = new boolean[count2];
1319 
1320         label: for (int i = 0; i<count1; i++) {
1321             XSParticleDecl particle1 = dChildren.get(i);
1322 
1323             for (int j = 0; j<count2; j++) {
1324                 XSParticleDecl particle2 = bChildren.get(j);
1325                 try {
1326                     particleValidRestriction(particle1, dSGHandler, particle2, bSGHandler);
1327                     if (foundIt[j])
1328                         throw new XMLSchemaException("rcase-RecurseUnordered.2", null);
1329                     else
1330                         foundIt[j]=true;
1331 
1332                     continue label;
1333                 }
1334                 catch (XMLSchemaException e) {
1335                 }
1336             }
1337             // didn't find a match.  Detect an error
1338             throw new XMLSchemaException("rcase-RecurseUnordered.2", null);
1339         }
1340 
1341         // Now, see if there are some elements in the base we didn't match up
1342         for (int j=0; j < count2; j++) {
1343             XSParticleDecl particle2 = bChildren.get(j);
1344             if (!foundIt[j] && !particle2.emptiable()) {
1345                 throw new XMLSchemaException("rcase-RecurseUnordered.2", null);
1346             }
1347         }
1348 
1349     }
1350 
1351     private static void checkRecurseLax(List<XSParticleDecl> dChildren, int min1, int max1,
1352             SubstitutionGroupHandler dSGHandler,
1353             List<XSParticleDecl> bChildren, int min2, int max2,
1354             SubstitutionGroupHandler  bSGHandler)
1355         throws XMLSchemaException {
1356 
1357         // check Occurrence ranges
1358         if (!checkOccurrenceRange(min1,max1,min2,max2)) {
1359             throw new XMLSchemaException("rcase-RecurseLax.1", new Object[]{
1360                     Integer.toString(min1),
1361                     max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1),
1362                             Integer.toString(min2),
1363                             max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)});
1364         }
1365 
1366         int count1= dChildren.size();
1367         int count2 = bChildren.size();
1368 
1369         int current = 0;
1370         label: for (int i = 0; i<count1; i++) {
1371 
1372             XSParticleDecl particle1 = dChildren.get(i);
1373             for (int j = current; j<count2; j++) {
1374                 XSParticleDecl particle2 = bChildren.get(j);
1375                 current +=1;
1376                 try {
1377                     // IHR: go back one element on b list because the next element may match
1378                     // this as well.
1379                     if (particleValidRestriction(particle1, dSGHandler, particle2, bSGHandler))
1380                         current--;
1381                     continue label;
1382                 }
1383                 catch (XMLSchemaException e) {
1384                 }
1385             }
1386             // didn't find a match.  Detect an error
1387             throw new XMLSchemaException("rcase-RecurseLax.2", null);
1388 
1389         }
1390 
1391     }
1392 
1393     private static void checkMapAndSum(List<XSParticleDecl> dChildren, int min1, int max1,
1394             SubstitutionGroupHandler dSGHandler,
1395             List<XSParticleDecl> bChildren, int min2, int max2,
1396             SubstitutionGroupHandler bSGHandler)
1397         throws XMLSchemaException {
1398 
1399         // See if the sequence group is a valid restriction of the choice
1400 
1401         // Here is an example of a valid restriction:
1402         //   <choice minOccurs="2">
1403         //       <a/>
1404         //       <b/>
1405         //       <c/>
1406         //   </choice>
1407         //
1408         //   <sequence>
1409         //        <b/>
1410         //        <a/>
1411         //   </sequence>
1412 
1413         // check Occurrence ranges
1414         if (!checkOccurrenceRange(min1,max1,min2,max2)) {
1415             throw new XMLSchemaException("rcase-MapAndSum.2",
1416                     new Object[]{Integer.toString(min1),
1417                     max1==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max1),
1418                             Integer.toString(min2),
1419                             max2==SchemaSymbols.OCCURRENCE_UNBOUNDED?"unbounded":Integer.toString(max2)});
1420         }
1421 
1422         int count1 = dChildren.size();
1423         int count2 = bChildren.size();
1424 
1425         label: for (int i = 0; i<count1; i++) {
1426 
1427             XSParticleDecl particle1 = dChildren.get(i);
1428             for (int j = 0; j<count2; j++) {
1429                 XSParticleDecl particle2 = bChildren.get(j);
1430                 try {
1431                     particleValidRestriction(particle1, dSGHandler, particle2, bSGHandler);
1432                     continue label;
1433                 }
1434                 catch (XMLSchemaException e) {
1435                 }
1436             }
1437             // didn't find a match.  Detect an error
1438             throw new XMLSchemaException("rcase-MapAndSum.1", null);
1439         }
1440     }
1441     // to check whether two element overlap, as defined in constraint UPA
1442     public static boolean overlapUPA(XSElementDecl element1,
1443             XSElementDecl element2,
1444             SubstitutionGroupHandler sgHandler) {
1445         // if the two element have the same name and namespace,
1446         if (element1.fName == element2.fName &&
1447                 element1.fTargetNamespace == element2.fTargetNamespace) {
1448             return true;
1449         }
1450 
1451         // or if there is an element decl in element1's substitution group,
1452         // who has the same name/namespace with element2
1453         XSElementDecl[] subGroup = sgHandler.getSubstitutionGroup(element1);
1454         for (int i = subGroup.length-1; i >= 0; i--) {
1455             if (subGroup[i].fName == element2.fName &&
1456                     subGroup[i].fTargetNamespace == element2.fTargetNamespace) {
1457                 return true;
1458             }
1459         }
1460 
1461         // or if there is an element decl in element2's substitution group,
1462         // who has the same name/namespace with element1
1463         subGroup = sgHandler.getSubstitutionGroup(element2);
1464         for (int i = subGroup.length-1; i >= 0; i--) {
1465             if (subGroup[i].fName == element1.fName &&
1466                     subGroup[i].fTargetNamespace == element1.fTargetNamespace) {
1467                 return true;
1468             }
1469         }
1470 
1471         return false;
1472     }
1473 
1474     // to check whether an element overlaps with a wildcard,
1475     // as defined in constraint UPA
1476     public static boolean overlapUPA(XSElementDecl element,
1477             XSWildcardDecl wildcard,
1478             SubstitutionGroupHandler sgHandler) {
1479         // if the wildcard allows the element
1480         if (wildcard.allowNamespace(element.fTargetNamespace))
1481             return true;
1482 
1483         // or if the wildcard allows any element in the substitution group
1484         XSElementDecl[] subGroup = sgHandler.getSubstitutionGroup(element);
1485         for (int i = subGroup.length-1; i >= 0; i--) {
1486             if (wildcard.allowNamespace(subGroup[i].fTargetNamespace))
1487                 return true;
1488         }
1489 
1490         return false;
1491     }
1492 
1493     public static boolean overlapUPA(XSWildcardDecl wildcard1,
1494             XSWildcardDecl wildcard2) {
1495         // if the intersection of the two wildcard is not empty list
1496         XSWildcardDecl intersect = wildcard1.performIntersectionWith(wildcard2, wildcard1.fProcessContents);
1497         if (intersect == null ||
1498                 intersect.fType != XSWildcardDecl.NSCONSTRAINT_LIST ||
1499                 intersect.fNamespaceList.length != 0) {
1500             return true;
1501         }
1502 
1503         return false;
1504     }
1505 
1506     // call one of the above methods according to the type of decls
1507     public static boolean overlapUPA(Object decl1, Object decl2,
1508             SubstitutionGroupHandler sgHandler) {
1509         if (decl1 instanceof XSElementDecl) {
1510             if (decl2 instanceof XSElementDecl) {
1511                 return overlapUPA((XSElementDecl)decl1,
1512                         (XSElementDecl)decl2,
1513                         sgHandler);
1514             }
1515             else {
1516                 return overlapUPA((XSElementDecl)decl1,
1517                         (XSWildcardDecl)decl2,
1518                         sgHandler);
1519             }
1520         }
1521         else {
1522             if (decl2 instanceof XSElementDecl) {
1523                 return overlapUPA((XSElementDecl)decl2,
1524                         (XSWildcardDecl)decl1,
1525                         sgHandler);
1526             }
1527             else {
1528                 return overlapUPA((XSWildcardDecl)decl1,
1529                         (XSWildcardDecl)decl2);
1530             }
1531         }
1532     }
1533 
1534 } // class XSContraints