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