1 /* 2 * Copyright (c) 2017, 2018, 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.dtd; 22 23 import java.util.Iterator; 24 25 import com.sun.org.apache.xerces.internal.impl.Constants; 26 import com.sun.org.apache.xerces.internal.impl.RevalidationHandler; 27 import com.sun.org.apache.xerces.internal.impl.XMLEntityManager; 28 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter; 29 import com.sun.org.apache.xerces.internal.impl.dtd.models.ContentModelValidator; 30 import com.sun.org.apache.xerces.internal.impl.dv.DTDDVFactory; 31 import com.sun.org.apache.xerces.internal.impl.dv.DatatypeValidator; 32 import com.sun.org.apache.xerces.internal.impl.dv.InvalidDatatypeValueException; 33 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter; 34 import com.sun.org.apache.xerces.internal.impl.validation.ValidationManager; 35 import com.sun.org.apache.xerces.internal.impl.validation.ValidationState; 36 import com.sun.org.apache.xerces.internal.util.SymbolTable; 37 import com.sun.org.apache.xerces.internal.util.XMLChar; 38 import com.sun.org.apache.xerces.internal.util.XMLSymbols; 39 import com.sun.org.apache.xerces.internal.xni.Augmentations; 40 import com.sun.org.apache.xerces.internal.xni.NamespaceContext; 41 import com.sun.org.apache.xerces.internal.xni.QName; 42 import com.sun.org.apache.xerces.internal.xni.XMLAttributes; 43 import com.sun.org.apache.xerces.internal.xni.XMLDocumentHandler; 44 import com.sun.org.apache.xerces.internal.xni.XMLLocator; 45 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier; 46 import com.sun.org.apache.xerces.internal.xni.XMLString; 47 import com.sun.org.apache.xerces.internal.xni.XNIException; 48 import com.sun.org.apache.xerces.internal.xni.grammars.Grammar; 49 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription; 50 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool; 51 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent; 52 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager; 53 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; 54 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentFilter; 55 import com.sun.org.apache.xerces.internal.xni.parser.XMLDocumentSource; 56 57 /** 58 * The DTD validator. The validator implements a document 59 * filter: receiving document events from the scanner; validating 60 * the content and structure; augmenting the InfoSet, if applicable; 61 * and notifying the parser of the information resulting from the 62 * validation process. 63 * <p> Formerly, this component also handled DTD events and grammar construction. 64 * To facilitate the development of a meaningful DTD grammar caching/preparsing 65 * framework, this functionality has been moved into the XMLDTDLoader 66 * class. Therefore, this class no longer implements the DTDFilter 67 * or DTDContentModelFilter interfaces. 68 * <p> 69 * This component requires the following features and properties from the 70 * component manager that uses it: 71 * <ul> 72 * <li>http://xml.org/sax/features/namespaces</li> 73 * <li>http://xml.org/sax/features/validation</li> 74 * <li>http://apache.org/xml/features/validation/dynamic</li> 75 * <li>http://apache.org/xml/properties/internal/symbol-table</li> 76 * <li>http://apache.org/xml/properties/internal/error-reporter</li> 77 * <li>http://apache.org/xml/properties/internal/grammar-pool</li> 78 * <li>http://apache.org/xml/properties/internal/datatype-validator-factory</li> 79 * </ul> 80 * 81 * @xerces.internal 82 * 83 * @author Eric Ye, IBM 84 * @author Andy Clark, IBM 85 * @author Jeffrey Rodriguez IBM 86 * @author Neil Graham, IBM 87 * 88 * @LastModified: May 2018 89 */ 90 public class XMLDTDValidator 91 implements XMLComponent, XMLDocumentFilter, XMLDTDValidatorFilter, RevalidationHandler { 92 93 // 94 // Constants 95 // 96 97 // feature identifiers 98 99 /** Feature identifier: namespaces. */ 100 protected static final String NAMESPACES = 101 Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE; 102 103 /** Feature identifier: validation. */ 104 protected static final String VALIDATION = 105 Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; 106 107 /** Feature identifier: dynamic validation. */ 108 protected static final String DYNAMIC_VALIDATION = 109 Constants.XERCES_FEATURE_PREFIX + Constants.DYNAMIC_VALIDATION_FEATURE; 110 111 /** Feature identifier: balance syntax trees. */ 112 protected static final String BALANCE_SYNTAX_TREES = 113 Constants.XERCES_FEATURE_PREFIX + Constants.BALANCE_SYNTAX_TREES; 114 115 /** Feature identifier: warn on duplicate attdef */ 116 protected static final String WARN_ON_DUPLICATE_ATTDEF = 117 Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_DUPLICATE_ATTDEF_FEATURE; 118 119 protected static final String PARSER_SETTINGS = 120 Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS; 121 122 123 // property identifiers 124 125 /** Property identifier: symbol table. */ 126 protected static final String SYMBOL_TABLE = 127 Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; 128 129 /** Property identifier: error reporter. */ 130 protected static final String ERROR_REPORTER = 131 Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; 132 133 /** Property identifier: grammar pool. */ 134 protected static final String GRAMMAR_POOL = 135 Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; 136 137 /** Property identifier: datatype validator factory. */ 138 protected static final String DATATYPE_VALIDATOR_FACTORY = 139 Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY; 140 141 // property identifier: ValidationManager 142 protected static final String VALIDATION_MANAGER = 143 Constants.XERCES_PROPERTY_PREFIX + Constants.VALIDATION_MANAGER_PROPERTY; 144 145 // recognized features and properties 146 147 /** Recognized features. */ 148 private static final String[] RECOGNIZED_FEATURES = { 149 NAMESPACES, 150 VALIDATION, 151 DYNAMIC_VALIDATION, 152 BALANCE_SYNTAX_TREES 153 }; 154 155 /** Feature defaults. */ 156 private static final Boolean[] FEATURE_DEFAULTS = { 157 null, 158 null, 159 Boolean.FALSE, 160 Boolean.FALSE, 161 }; 162 163 /** Recognized properties. */ 164 private static final String[] RECOGNIZED_PROPERTIES = { 165 SYMBOL_TABLE, 166 ERROR_REPORTER, 167 GRAMMAR_POOL, 168 DATATYPE_VALIDATOR_FACTORY, 169 VALIDATION_MANAGER 170 }; 171 172 /** Property defaults. */ 173 private static final Object[] PROPERTY_DEFAULTS = { 174 null, 175 null, 176 null, 177 null, 178 null, 179 }; 180 181 // debugging 182 183 /** Compile to true to debug attributes. */ 184 private static final boolean DEBUG_ATTRIBUTES = false; 185 186 /** Compile to true to debug element children. */ 187 private static final boolean DEBUG_ELEMENT_CHILDREN = false; 188 189 // 190 // Data 191 // 192 193 // updated during reset 194 protected ValidationManager fValidationManager = null; 195 196 // validation state 197 protected final ValidationState fValidationState = new ValidationState(); 198 199 // features 200 201 /** Namespaces. */ 202 protected boolean fNamespaces; 203 204 /** Validation. */ 205 protected boolean fValidation; 206 207 /** Validation against only DTD */ 208 protected boolean fDTDValidation; 209 210 /** 211 * Dynamic validation. This state of this feature is only useful when 212 * the validation feature is set to <code>true</code>. 213 */ 214 protected boolean fDynamicValidation; 215 216 /** Controls whether the DTD grammar produces balanced syntax trees. */ 217 protected boolean fBalanceSyntaxTrees; 218 219 /** warn on duplicate attribute definition, this feature works only when validation is true */ 220 protected boolean fWarnDuplicateAttdef; 221 222 // properties 223 224 /** Symbol table. */ 225 protected SymbolTable fSymbolTable; 226 227 /** Error reporter. */ 228 protected XMLErrorReporter fErrorReporter; 229 230 // the grammar pool 231 protected XMLGrammarPool fGrammarPool; 232 233 /** Grammar bucket. */ 234 protected DTDGrammarBucket fGrammarBucket; 235 236 /* location of the document as passed in from startDocument call */ 237 protected XMLLocator fDocLocation; 238 239 /** Namespace support. */ 240 protected NamespaceContext fNamespaceContext = null; 241 242 /** Datatype validator factory. */ 243 protected DTDDVFactory fDatatypeValidatorFactory; 244 245 // handlers 246 247 /** Document handler. */ 248 protected XMLDocumentHandler fDocumentHandler; 249 250 protected XMLDocumentSource fDocumentSource; 251 // grammars 252 253 /** DTD Grammar. */ 254 protected DTDGrammar fDTDGrammar; 255 256 // state 257 258 /** True if seen DOCTYPE declaration. */ 259 protected boolean fSeenDoctypeDecl = false; 260 261 /** Perform validation. */ 262 private boolean fPerformValidation; 263 264 /** Schema type: None, DTD, Schema */ 265 private String fSchemaType; 266 267 // information regarding the current element 268 269 /** Current element name. */ 270 private final QName fCurrentElement = new QName(); 271 272 /** Current element index. */ 273 private int fCurrentElementIndex = -1; 274 275 /** Current content spec type. */ 276 private int fCurrentContentSpecType = -1; 277 278 /** The root element name. */ 279 private final QName fRootElement = new QName(); 280 281 private boolean fInCDATASection = false; 282 // element stack 283 284 /** Element index stack. */ 285 private int[] fElementIndexStack = new int[8]; 286 287 /** Content spec type stack. */ 288 private int[] fContentSpecTypeStack = new int[8]; 289 290 /** Element name stack. */ 291 private QName[] fElementQNamePartsStack = new QName[8]; 292 293 // children list and offset stack 294 295 /** 296 * Element children. This data structure is a growing stack that 297 * holds the children of elements from the root to the current 298 * element depth. This structure never gets "deeper" than the 299 * deepest element. Space is re-used once each element is closed. 300 * <p> 301 * <strong>Note:</strong> This is much more efficient use of memory 302 * than creating new arrays for each element depth. 303 * <p> 304 * <strong>Note:</strong> The use of this data structure is for 305 * validation "on the way out". If the validation model changes to 306 * "on the way in", then this data structure is not needed. 307 */ 308 private QName[] fElementChildren = new QName[32]; 309 310 /** Element children count. */ 311 private int fElementChildrenLength = 0; 312 313 /** 314 * Element children offset stack. This stack refers to offsets 315 * into the <code>fElementChildren</code> array. 316 * @see #fElementChildren 317 */ 318 private int[] fElementChildrenOffsetStack = new int[32]; 319 320 /** Element depth. */ 321 private int fElementDepth = -1; 322 323 // validation states 324 325 /** True if seen the root element. */ 326 private boolean fSeenRootElement = false; 327 328 /** True if inside of element content. */ 329 private boolean fInElementContent = false; 330 331 // temporary variables 332 333 /** Temporary element declaration. */ 334 private final XMLElementDecl fTempElementDecl = new XMLElementDecl(); 335 336 /** Temporary atribute declaration. */ 337 private final XMLAttributeDecl fTempAttDecl = new XMLAttributeDecl(); 338 339 /** Temporary entity declaration. */ 340 private final XMLEntityDecl fEntityDecl = new XMLEntityDecl(); 341 342 /** Temporary qualified name. */ 343 private final QName fTempQName = new QName(); 344 345 /** Temporary string buffers. */ 346 private final StringBuilder fBuffer = new StringBuilder(); 347 348 // symbols: general 349 350 // attribute validators 351 352 /** Datatype validator: ID. */ 353 protected DatatypeValidator fValID; 354 355 /** Datatype validator: IDREF. */ 356 protected DatatypeValidator fValIDRef; 357 358 /** Datatype validator: IDREFS. */ 359 protected DatatypeValidator fValIDRefs; 360 361 /** Datatype validator: ENTITY. */ 362 protected DatatypeValidator fValENTITY; 363 364 /** Datatype validator: ENTITIES. */ 365 protected DatatypeValidator fValENTITIES; 366 367 /** Datatype validator: NMTOKEN. */ 368 protected DatatypeValidator fValNMTOKEN; 369 370 /** Datatype validator: NMTOKENS. */ 371 protected DatatypeValidator fValNMTOKENS; 372 373 /** Datatype validator: NOTATION. */ 374 protected DatatypeValidator fValNOTATION; 375 376 // to check for duplicate ID or ANNOTATION attribute declare in 377 // ATTLIST, and misc VCs 378 379 // 380 // Constructors 381 // 382 383 /** Default constructor. */ XMLDTDValidator()384 public XMLDTDValidator() { 385 386 // initialize data 387 for (int i = 0; i < fElementQNamePartsStack.length; i++) { 388 fElementQNamePartsStack[i] = new QName(); 389 } 390 fGrammarBucket = new DTDGrammarBucket(); 391 392 } // <init>() 393 getGrammarBucket()394 DTDGrammarBucket getGrammarBucket() { 395 return fGrammarBucket; 396 } // getGrammarBucket(): DTDGrammarBucket 397 398 // 399 // XMLComponent methods 400 // 401 402 /* 403 * Resets the component. The component can query the component manager 404 * about any features and properties that affect the operation of the 405 * component. 406 * 407 * @param componentManager The component manager. 408 * 409 * @throws SAXException Thrown by component on finitialization error. 410 * For example, if a feature or property is 411 * required for the operation of the component, the 412 * component manager may throw a 413 * SAXNotRecognizedException or a 414 * SAXNotSupportedException. 415 */ reset(XMLComponentManager componentManager)416 public void reset(XMLComponentManager componentManager) 417 throws XMLConfigurationException { 418 419 // clear grammars 420 fDTDGrammar = null; 421 fSeenDoctypeDecl = false; 422 fInCDATASection = false; 423 // initialize state 424 fSeenRootElement = false; 425 fInElementContent = false; 426 fCurrentElementIndex = -1; 427 fCurrentContentSpecType = -1; 428 429 fRootElement.clear(); 430 431 fValidationState.resetIDTables(); 432 433 fGrammarBucket.clear(); 434 fElementDepth = -1; 435 fElementChildrenLength = 0; 436 437 boolean parser_settings = componentManager.getFeature(PARSER_SETTINGS, true); 438 439 if (!parser_settings){ 440 // parser settings have not been changed 441 fValidationManager.addValidationState(fValidationState); 442 return; 443 } 444 445 // sax features 446 fNamespaces = componentManager.getFeature(NAMESPACES, true); 447 fValidation = componentManager.getFeature(VALIDATION, false); 448 fDTDValidation = !(componentManager.getFeature(Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE, false)); 449 450 // Xerces features 451 fDynamicValidation = componentManager.getFeature(DYNAMIC_VALIDATION, false); 452 fBalanceSyntaxTrees = componentManager.getFeature(BALANCE_SYNTAX_TREES, false); 453 fWarnDuplicateAttdef = componentManager.getFeature(WARN_ON_DUPLICATE_ATTDEF, false); 454 455 fSchemaType = (String)componentManager.getProperty (Constants.JAXP_PROPERTY_PREFIX 456 + Constants.SCHEMA_LANGUAGE, null); 457 458 fValidationManager= (ValidationManager)componentManager.getProperty(VALIDATION_MANAGER); 459 fValidationManager.addValidationState(fValidationState); 460 fValidationState.setUsingNamespaces(fNamespaces); 461 462 // get needed components 463 fErrorReporter = (XMLErrorReporter)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX+Constants.ERROR_REPORTER_PROPERTY); 464 fSymbolTable = (SymbolTable)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX+Constants.SYMBOL_TABLE_PROPERTY); 465 fGrammarPool= (XMLGrammarPool)componentManager.getProperty(GRAMMAR_POOL, null); 466 467 fDatatypeValidatorFactory = (DTDDVFactory)componentManager.getProperty(Constants.XERCES_PROPERTY_PREFIX + Constants.DATATYPE_VALIDATOR_FACTORY_PROPERTY); 468 init(); 469 470 } // reset(XMLComponentManager) 471 472 /** 473 * Returns a list of feature identifiers that are recognized by 474 * this component. This method may return null if no features 475 * are recognized by this component. 476 */ getRecognizedFeatures()477 public String[] getRecognizedFeatures() { 478 return RECOGNIZED_FEATURES.clone(); 479 } // getRecognizedFeatures():String[] 480 481 /** 482 * Sets the state of a feature. This method is called by the component 483 * manager any time after reset when a feature changes state. 484 * <p> 485 * <strong>Note:</strong> Components should silently ignore features 486 * that do not affect the operation of the component. 487 * 488 * @param featureId The feature identifier. 489 * @param state The state of the feature. 490 */ setFeature(String featureId, boolean state)491 public void setFeature(String featureId, boolean state) 492 throws XMLConfigurationException { 493 } // setFeature(String,boolean) 494 495 /** 496 * Returns a list of property identifiers that are recognized by 497 * this component. This method may return null if no properties 498 * are recognized by this component. 499 */ getRecognizedProperties()500 public String[] getRecognizedProperties() { 501 return RECOGNIZED_PROPERTIES.clone(); 502 } // getRecognizedProperties():String[] 503 504 /** 505 * Sets the value of a property. This method is called by the component 506 * manager any time after reset when a property changes value. 507 * <p> 508 * <strong>Note:</strong> Components should silently ignore properties 509 * that do not affect the operation of the component. 510 * 511 * @param propertyId The property identifier. 512 * @param value The value of the property. 513 */ setProperty(String propertyId, Object value)514 public void setProperty(String propertyId, Object value) 515 throws XMLConfigurationException { 516 } // setProperty(String,Object) 517 518 /** 519 * Returns the default state for a feature, or null if this 520 * component does not want to report a default value for this 521 * feature. 522 * 523 * @param featureId The feature identifier. 524 * 525 * @since Xerces 2.2.0 526 */ getFeatureDefault(String featureId)527 public Boolean getFeatureDefault(String featureId) { 528 for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { 529 if (RECOGNIZED_FEATURES[i].equals(featureId)) { 530 return FEATURE_DEFAULTS[i]; 531 } 532 } 533 return null; 534 } // getFeatureDefault(String):Boolean 535 536 /** 537 * Returns the default state for a property, or null if this 538 * component does not want to report a default value for this 539 * property. 540 * 541 * @param propertyId The property identifier. 542 * 543 * @since Xerces 2.2.0 544 */ getPropertyDefault(String propertyId)545 public Object getPropertyDefault(String propertyId) { 546 for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { 547 if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { 548 return PROPERTY_DEFAULTS[i]; 549 } 550 } 551 return null; 552 } // getPropertyDefault(String):Object 553 554 // 555 // XMLDocumentSource methods 556 // 557 558 /** Sets the document handler to receive information about the document. */ setDocumentHandler(XMLDocumentHandler documentHandler)559 public void setDocumentHandler(XMLDocumentHandler documentHandler) { 560 fDocumentHandler = documentHandler; 561 } // setDocumentHandler(XMLDocumentHandler) 562 563 /** Returns the document handler */ getDocumentHandler()564 public XMLDocumentHandler getDocumentHandler() { 565 return fDocumentHandler; 566 } // getDocumentHandler(): XMLDocumentHandler 567 568 569 // 570 // XMLDocumentHandler methods 571 // 572 573 /** Sets the document source */ setDocumentSource(XMLDocumentSource source)574 public void setDocumentSource(XMLDocumentSource source){ 575 fDocumentSource = source; 576 } // setDocumentSource 577 578 /** Returns the document source */ getDocumentSource()579 public XMLDocumentSource getDocumentSource (){ 580 return fDocumentSource; 581 } // getDocumentSource 582 583 /** 584 * The start of the document. 585 * 586 * @param locator The system identifier of the entity if the entity 587 * is external, null otherwise. 588 * @param encoding The auto-detected IANA encoding name of the entity 589 * stream. This value will be null in those situations 590 * where the entity encoding is not auto-detected (e.g. 591 * internal entities or a document entity that is 592 * parsed from a java.io.Reader). 593 * @param namespaceContext 594 * The namespace context in effect at the 595 * start of this document. 596 * This object represents the current context. 597 * Implementors of this class are responsible 598 * for copying the namespace bindings from the 599 * the current context (and its parent contexts) 600 * if that information is important. 601 * @param augs Additional information that may include infoset augmentations 602 * 603 * @throws XNIException Thrown by handler to signal an error. 604 */ startDocument(XMLLocator locator, String encoding, NamespaceContext namespaceContext, Augmentations augs)605 public void startDocument(XMLLocator locator, String encoding, 606 NamespaceContext namespaceContext, Augmentations augs) 607 throws XNIException { 608 609 // call handlers 610 // get initial grammars 611 if (fGrammarPool != null) { 612 Grammar [] grammars = fGrammarPool.retrieveInitialGrammarSet(XMLGrammarDescription.XML_DTD); 613 final int length = (grammars != null) ? grammars.length : 0; 614 for (int i = 0; i < length; ++i) { 615 fGrammarBucket.putGrammar((DTDGrammar)grammars[i]); 616 } 617 } 618 fDocLocation = locator; 619 fNamespaceContext = namespaceContext; 620 621 if (fDocumentHandler != null) { 622 fDocumentHandler.startDocument(locator, encoding, namespaceContext, augs); 623 } 624 625 } // startDocument(XMLLocator,String) 626 627 /** 628 * Notifies of the presence of an XMLDecl line in the document. If 629 * present, this method will be called immediately following the 630 * startDocument call. 631 * 632 * @param version The XML version. 633 * @param encoding The IANA encoding name of the document, or null if 634 * not specified. 635 * @param standalone The standalone value, or null if not specified. 636 * @param augs Additional information that may include infoset augmentations 637 * 638 * @throws XNIException Thrown by handler to signal an error. 639 */ xmlDecl(String version, String encoding, String standalone, Augmentations augs)640 public void xmlDecl(String version, String encoding, String standalone, Augmentations augs) 641 throws XNIException { 642 643 // save standalone state 644 fGrammarBucket.setStandalone(standalone != null && standalone.equals("yes")); 645 646 // call handlers 647 if (fDocumentHandler != null) { 648 fDocumentHandler.xmlDecl(version, encoding, standalone, augs); 649 } 650 651 } // xmlDecl(String,String,String) 652 653 /** 654 * Notifies of the presence of the DOCTYPE line in the document. 655 * 656 * @param rootElement The name of the root element. 657 * @param publicId The public identifier if an external DTD or null 658 * if the external DTD is specified using SYSTEM. 659 * @param systemId The system identifier if an external DTD, null 660 * otherwise. 661 * @param augs Additional information that may include infoset augmentations 662 * 663 * @throws XNIException Thrown by handler to signal an error. 664 */ doctypeDecl(String rootElement, String publicId, String systemId, Augmentations augs)665 public void doctypeDecl(String rootElement, String publicId, String systemId, 666 Augmentations augs) 667 throws XNIException { 668 669 // save root element state 670 fSeenDoctypeDecl = true; 671 fRootElement.setValues(null, rootElement, rootElement, null); 672 // find or create grammar: 673 String eid = null; 674 try { 675 eid = XMLEntityManager.expandSystemId(systemId, fDocLocation.getExpandedSystemId(), false); 676 } catch (java.io.IOException e) { 677 } 678 XMLDTDDescription grammarDesc = new XMLDTDDescription(publicId, systemId, fDocLocation.getExpandedSystemId(), eid, rootElement); 679 fDTDGrammar = fGrammarBucket.getGrammar(grammarDesc); 680 if(fDTDGrammar == null) { 681 // give grammar pool a chance... 682 // 683 // Do not bother checking the pool if no public or system identifier was provided. 684 // Since so many different DTDs have roots in common, using only a root name as the 685 // key may cause an unexpected grammar to be retrieved from the grammar pool. This scenario 686 // would occur when an ExternalSubsetResolver has been queried and the 687 // XMLInputSource returned contains an input stream but no external identifier. 688 // This can never happen when the instance document specified a DOCTYPE. -- mrglavas 689 if (fGrammarPool != null && (systemId != null || publicId != null)) { 690 fDTDGrammar = (DTDGrammar)fGrammarPool.retrieveGrammar(grammarDesc); 691 } 692 } 693 if(fDTDGrammar == null) { 694 // we'll have to create it... 695 if (!fBalanceSyntaxTrees) { 696 fDTDGrammar = new DTDGrammar(fSymbolTable, grammarDesc); 697 } 698 else { 699 fDTDGrammar = new BalancedDTDGrammar(fSymbolTable, grammarDesc); 700 } 701 } else { 702 // we've found a cached one;so let's make sure not to read 703 // any external subset! 704 fValidationManager.setCachedDTD(true); 705 } 706 fGrammarBucket.setActiveGrammar(fDTDGrammar); 707 708 // call handlers 709 if (fDocumentHandler != null) { 710 fDocumentHandler.doctypeDecl(rootElement, publicId, systemId, augs); 711 } 712 713 } // doctypeDecl(String,String,String, Augmentations) 714 715 716 /** 717 * The start of an element. 718 * 719 * @param element The name of the element. 720 * @param attributes The element attributes. 721 * @param augs Additional information that may include infoset augmentations 722 * 723 * @throws XNIException Thrown by handler to signal an error. 724 */ startElement(QName element, XMLAttributes attributes, Augmentations augs)725 public void startElement(QName element, XMLAttributes attributes, Augmentations augs) 726 throws XNIException { 727 728 handleStartElement(element, attributes, augs); 729 // call handlers 730 if (fDocumentHandler != null) { 731 fDocumentHandler.startElement(element, attributes, augs); 732 733 } 734 735 } // startElement(QName,XMLAttributes) 736 737 /** 738 * An empty element. 739 * 740 * @param element The name of the element. 741 * @param attributes The element attributes. 742 * @param augs Additional information that may include infoset augmentations 743 * 744 * @throws XNIException Thrown by handler to signal an error. 745 */ emptyElement(QName element, XMLAttributes attributes, Augmentations augs)746 public void emptyElement(QName element, XMLAttributes attributes, Augmentations augs) 747 throws XNIException { 748 749 boolean removed = handleStartElement(element, attributes, augs); 750 751 if (fDocumentHandler !=null) { 752 fDocumentHandler.emptyElement(element, attributes, augs); 753 } 754 if (!removed) { 755 handleEndElement(element, augs, true); 756 } 757 758 759 } // emptyElement(QName,XMLAttributes) 760 761 /** 762 * Character content. 763 * 764 * @param text The content. 765 * 766 * @param augs Additional information that may include infoset augmentations 767 * 768 * @throws XNIException Thrown by handler to signal an error. 769 */ characters(XMLString text, Augmentations augs)770 public void characters(XMLString text, Augmentations augs) throws XNIException { 771 772 boolean callNextCharacters = true; 773 774 // REVISIT: [Q] Is there a more efficient way of doing this? 775 // Perhaps if the scanner told us so we don't have to 776 // look at the characters again. -Ac 777 boolean allWhiteSpace = true; 778 for (int i=text.offset; i< text.offset+text.length; i++) { 779 if (!isSpace(text.ch[i])) { 780 allWhiteSpace = false; 781 break; 782 } 783 } 784 // call the ignoreableWhiteSpace callback 785 // never call ignorableWhitespace if we are in cdata section 786 if (fInElementContent && allWhiteSpace && !fInCDATASection) { 787 if (fDocumentHandler != null) { 788 fDocumentHandler.ignorableWhitespace(text, augs); 789 callNextCharacters = false; 790 } 791 } 792 793 // validate 794 if (fPerformValidation) { 795 if (fInElementContent) { 796 if (fGrammarBucket.getStandalone() && 797 fDTDGrammar.getElementDeclIsExternal(fCurrentElementIndex)) { 798 if (allWhiteSpace) { 799 fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN, 800 "MSG_WHITE_SPACE_IN_ELEMENT_CONTENT_WHEN_STANDALONE", 801 null, XMLErrorReporter.SEVERITY_ERROR); 802 } 803 } 804 if (!allWhiteSpace) { 805 charDataInContent(); 806 } 807 808 // For E15.2 809 if (augs != null && augs.getItem(Constants.CHAR_REF_PROBABLE_WS) == Boolean.TRUE) { 810 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 811 "MSG_CONTENT_INVALID_SPECIFIED", 812 new Object[]{ fCurrentElement.rawname, 813 fDTDGrammar.getContentSpecAsString(fElementDepth), 814 "character reference"}, 815 XMLErrorReporter.SEVERITY_ERROR); 816 } 817 } 818 819 if (fCurrentContentSpecType == XMLElementDecl.TYPE_EMPTY) { 820 charDataInContent(); 821 } 822 } 823 824 // call handlers 825 if (callNextCharacters && fDocumentHandler != null) { 826 fDocumentHandler.characters(text, augs); 827 } 828 829 } // characters(XMLString) 830 831 832 833 /** 834 * Ignorable whitespace. For this method to be called, the document 835 * source must have some way of determining that the text containing 836 * only whitespace characters should be considered ignorable. For 837 * example, the validator can determine if a length of whitespace 838 * characters in the document are ignorable based on the element 839 * content model. 840 * 841 * @param text The ignorable whitespace. 842 * @param augs Additional information that may include infoset augmentations 843 * 844 * @throws XNIException Thrown by handler to signal an error. 845 */ ignorableWhitespace(XMLString text, Augmentations augs)846 public void ignorableWhitespace(XMLString text, Augmentations augs) throws XNIException { 847 848 // call handlers 849 if (fDocumentHandler != null) { 850 fDocumentHandler.ignorableWhitespace(text, augs); 851 } 852 853 } // ignorableWhitespace(XMLString) 854 855 /** 856 * The end of an element. 857 * 858 * @param element The name of the element. 859 * @param augs Additional information that may include infoset augmentations 860 * 861 * @throws XNIException Thrown by handler to signal an error. 862 */ endElement(QName element, Augmentations augs)863 public void endElement(QName element, Augmentations augs) throws XNIException { 864 865 handleEndElement(element, augs, false); 866 867 } // endElement(QName) 868 869 /** 870 * The start of a CDATA section. 871 * @param augs Additional information that may include infoset augmentations 872 * 873 * @throws XNIException Thrown by handler to signal an error. 874 */ startCDATA(Augmentations augs)875 public void startCDATA(Augmentations augs) throws XNIException { 876 877 if (fPerformValidation && fInElementContent) { 878 charDataInContent(); 879 } 880 fInCDATASection = true; 881 // call handlers 882 if (fDocumentHandler != null) { 883 fDocumentHandler.startCDATA(augs); 884 } 885 886 } // startCDATA() 887 888 /** 889 * The end of a CDATA section. 890 * @param augs Additional information that may include infoset augmentations 891 * 892 * @throws XNIException Thrown by handler to signal an error. 893 */ endCDATA(Augmentations augs)894 public void endCDATA(Augmentations augs) throws XNIException { 895 896 fInCDATASection = false; 897 // call handlers 898 if (fDocumentHandler != null) { 899 fDocumentHandler.endCDATA(augs); 900 } 901 902 } // endCDATA() 903 904 /** 905 * The end of the document. 906 * @param augs Additional information that may include infoset augmentations 907 * 908 * @throws XNIException Thrown by handler to signal an error. 909 */ endDocument(Augmentations augs)910 public void endDocument(Augmentations augs) throws XNIException { 911 912 // call handlers 913 if (fDocumentHandler != null) { 914 fDocumentHandler.endDocument(augs); 915 } 916 917 } // endDocument() 918 919 /** 920 * A comment. 921 * 922 * @param text The text in the comment. 923 * @param augs Additional information that may include infoset augmentations 924 * 925 * @throws XNIException Thrown by application to signal an error. 926 */ comment(XMLString text, Augmentations augs)927 public void comment(XMLString text, Augmentations augs) throws XNIException { 928 // fixes E15.1 929 if (fPerformValidation && fElementDepth >= 0 && fDTDGrammar != null) { 930 fDTDGrammar.getElementDecl(fCurrentElementIndex, fTempElementDecl); 931 if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) { 932 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 933 "MSG_CONTENT_INVALID_SPECIFIED", 934 new Object[]{ fCurrentElement.rawname, 935 "EMPTY", 936 "comment"}, 937 XMLErrorReporter.SEVERITY_ERROR); 938 } 939 } 940 // call handlers 941 if (fDocumentHandler != null) { 942 fDocumentHandler.comment(text, augs); 943 } 944 945 } // comment(XMLString) 946 947 948 /** 949 * A processing instruction. Processing instructions consist of a 950 * target name and, optionally, text data. The data is only meaningful 951 * to the application. 952 * <p> 953 * Typically, a processing instruction's data will contain a series 954 * of pseudo-attributes. These pseudo-attributes follow the form of 955 * element attributes but are <strong>not</strong> parsed or presented 956 * to the application as anything other than text. The application is 957 * responsible for parsing the data. 958 * 959 * @param target The target. 960 * @param data The data or null if none specified. 961 * @param augs Additional information that may include infoset augmentations 962 * 963 * @throws XNIException Thrown by handler to signal an error. 964 */ processingInstruction(String target, XMLString data, Augmentations augs)965 public void processingInstruction(String target, XMLString data, Augmentations augs) 966 throws XNIException { 967 968 // fixes E15.1 969 if (fPerformValidation && fElementDepth >= 0 && fDTDGrammar != null) { 970 fDTDGrammar.getElementDecl(fCurrentElementIndex, fTempElementDecl); 971 if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) { 972 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 973 "MSG_CONTENT_INVALID_SPECIFIED", 974 new Object[]{ fCurrentElement.rawname, 975 "EMPTY", 976 "processing instruction"}, 977 XMLErrorReporter.SEVERITY_ERROR); 978 } 979 } 980 // call handlers 981 if (fDocumentHandler != null) { 982 fDocumentHandler.processingInstruction(target, data, augs); 983 } 984 } // processingInstruction(String,XMLString) 985 986 /** 987 * This method notifies the start of a general entity. 988 * <p> 989 * <strong>Note:</strong> This method is not called for entity references 990 * appearing as part of attribute values. 991 * 992 * @param name The name of the general entity. 993 * @param identifier The resource identifier. 994 * @param encoding The auto-detected IANA encoding name of the entity 995 * stream. This value will be null in those situations 996 * where the entity encoding is not auto-detected (e.g. 997 * internal entities or a document entity that is 998 * parsed from a java.io.Reader). 999 * @param augs Additional information that may include infoset augmentations 1000 * 1001 * @exception XNIException Thrown by handler to signal an error. 1002 */ startGeneralEntity(String name, XMLResourceIdentifier identifier, String encoding, Augmentations augs)1003 public void startGeneralEntity(String name, 1004 XMLResourceIdentifier identifier, 1005 String encoding, 1006 Augmentations augs) throws XNIException { 1007 if (fPerformValidation && fElementDepth >= 0 && fDTDGrammar != null) { 1008 fDTDGrammar.getElementDecl(fCurrentElementIndex, fTempElementDecl); 1009 // fixes E15.1 1010 if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) { 1011 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1012 "MSG_CONTENT_INVALID_SPECIFIED", 1013 new Object[]{ fCurrentElement.rawname, 1014 "EMPTY", "ENTITY"}, 1015 XMLErrorReporter.SEVERITY_ERROR); 1016 } 1017 if (fGrammarBucket.getStandalone()) { 1018 XMLDTDLoader.checkStandaloneEntityRef(name, fDTDGrammar, fEntityDecl, fErrorReporter); 1019 } 1020 } 1021 if (fDocumentHandler != null) { 1022 fDocumentHandler.startGeneralEntity(name, identifier, encoding, augs); 1023 } 1024 } 1025 1026 /** 1027 * This method notifies the end of a general entity. 1028 * <p> 1029 * <strong>Note:</strong> This method is not called for entity references 1030 * appearing as part of attribute values. 1031 * 1032 * @param name The name of the entity. 1033 * @param augs Additional information that may include infoset augmentations 1034 * 1035 * @exception XNIException 1036 * Thrown by handler to signal an error. 1037 */ endGeneralEntity(String name, Augmentations augs)1038 public void endGeneralEntity(String name, Augmentations augs) throws XNIException { 1039 // call handlers 1040 if (fDocumentHandler != null) { 1041 fDocumentHandler.endGeneralEntity(name, augs); 1042 } 1043 } // endEntity(String) 1044 1045 /** 1046 * Notifies of the presence of a TextDecl line in an entity. If present, 1047 * this method will be called immediately following the startParameterEntity call. 1048 * <p> 1049 * <strong>Note:</strong> This method is only called for external 1050 * parameter entities referenced in the DTD. 1051 * 1052 * @param version The XML version, or null if not specified. 1053 * @param encoding The IANA encoding name of the entity. 1054 * @param augs Additional information that may include infoset 1055 * augmentations. 1056 * 1057 * @throws XNIException Thrown by handler to signal an error. 1058 */ textDecl(String version, String encoding, Augmentations augs)1059 public void textDecl(String version, String encoding, Augmentations augs) throws XNIException { 1060 1061 // call handlers 1062 if (fDocumentHandler != null) { 1063 fDocumentHandler.textDecl(version, encoding, augs); 1064 } 1065 } 1066 1067 hasGrammar()1068 public final boolean hasGrammar(){ 1069 1070 return (fDTDGrammar != null); 1071 } 1072 validate()1073 public final boolean validate(){ 1074 // Do validation if all of the following are true: 1075 // 1. The JAXP Schema Language property is not XML Schema 1076 // REVISIT: since only DTD and Schema are supported at this time, 1077 // such checking is sufficient. but if more schema types 1078 // are introduced in the future, we'll need to change it 1079 // to something like 1080 // (fSchemaType == null || fSchemaType == NS_XML_DTD) 1081 // 2. One of the following is true (validation features) 1082 // 2.1 Dynamic validation is off, and validation is on 1083 // 2.2 Dynamic validation is on, and DOCTYPE was seen 1084 // 3 Xerces schema validation feature is off, or DOCTYPE was seen. 1085 return (fSchemaType != Constants.NS_XMLSCHEMA) && 1086 (!fDynamicValidation && fValidation || 1087 fDynamicValidation && fSeenDoctypeDecl) && 1088 (fDTDValidation || fSeenDoctypeDecl); 1089 } 1090 1091 //REVISIT:we can convert into functions.. adding default attribute values.. and one validating. 1092 1093 /** Add default attributes and validate. */ addDTDDefaultAttrsAndValidate(QName elementName, int elementIndex, XMLAttributes attributes)1094 protected void addDTDDefaultAttrsAndValidate(QName elementName, int elementIndex, 1095 XMLAttributes attributes) 1096 throws XNIException { 1097 1098 // is there anything to do? 1099 if (elementIndex == -1 || fDTDGrammar == null) { 1100 return; 1101 } 1102 1103 // 1104 // Check after all specified attrs are scanned 1105 // (1) report error for REQUIRED attrs that are missing (V_TAGc) 1106 // (2) add default attrs (FIXED and NOT_FIXED) 1107 // 1108 int attlistIndex = fDTDGrammar.getFirstAttributeDeclIndex(elementIndex); 1109 1110 while (attlistIndex != -1) { 1111 1112 fDTDGrammar.getAttributeDecl(attlistIndex, fTempAttDecl); 1113 1114 if (DEBUG_ATTRIBUTES) { 1115 if (fTempAttDecl != null) { 1116 XMLElementDecl elementDecl = new XMLElementDecl(); 1117 fDTDGrammar.getElementDecl(elementIndex, elementDecl); 1118 System.out.println("element: "+(elementDecl.name.localpart)); 1119 System.out.println("attlistIndex " + attlistIndex + "\n"+ 1120 "attName : '"+(fTempAttDecl.name.localpart) + "'\n" 1121 + "attType : "+fTempAttDecl.simpleType.type + "\n" 1122 + "attDefaultType : "+fTempAttDecl.simpleType.defaultType + "\n" 1123 + "attDefaultValue : '"+fTempAttDecl.simpleType.defaultValue + "'\n" 1124 + attributes.getLength() +"\n" 1125 ); 1126 } 1127 } 1128 String attPrefix = fTempAttDecl.name.prefix; 1129 String attLocalpart = fTempAttDecl.name.localpart; 1130 String attRawName = fTempAttDecl.name.rawname; 1131 String attType = getAttributeTypeName(fTempAttDecl); 1132 int attDefaultType =fTempAttDecl.simpleType.defaultType; 1133 String attValue = null; 1134 1135 if (fTempAttDecl.simpleType.defaultValue != null) { 1136 attValue = fTempAttDecl.simpleType.defaultValue; 1137 } 1138 1139 boolean specified = false; 1140 boolean required = attDefaultType == XMLSimpleType.DEFAULT_TYPE_REQUIRED; 1141 boolean cdata = attType == XMLSymbols.fCDATASymbol; 1142 1143 if (!cdata || required || attValue != null) { 1144 int attrCount = attributes.getLength(); 1145 for (int i = 0; i < attrCount; i++) { 1146 if (attributes.getQName(i) == attRawName) { 1147 specified = true; 1148 break; 1149 } 1150 } 1151 } 1152 1153 if (!specified) { 1154 if (required) { 1155 if (fPerformValidation) { 1156 Object[] args = {elementName.localpart, attRawName}; 1157 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1158 "MSG_REQUIRED_ATTRIBUTE_NOT_SPECIFIED", args, 1159 XMLErrorReporter.SEVERITY_ERROR); 1160 } 1161 } 1162 else if (attValue != null) { 1163 if (fPerformValidation && fGrammarBucket.getStandalone()) { 1164 if (fDTDGrammar.getAttributeDeclIsExternal(attlistIndex)) { 1165 1166 Object[] args = { elementName.localpart, attRawName}; 1167 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1168 "MSG_DEFAULTED_ATTRIBUTE_NOT_SPECIFIED", args, 1169 XMLErrorReporter.SEVERITY_ERROR); 1170 } 1171 } 1172 1173 // add namespace information 1174 if (fNamespaces) { 1175 int index = attRawName.indexOf(':'); 1176 if (index != -1) { 1177 attPrefix = attRawName.substring(0, index); 1178 attPrefix = fSymbolTable.addSymbol(attPrefix); 1179 attLocalpart = attRawName.substring(index + 1); 1180 attLocalpart = fSymbolTable.addSymbol(attLocalpart); 1181 } 1182 } 1183 1184 // add attribute 1185 fTempQName.setValues(attPrefix, attLocalpart, attRawName, fTempAttDecl.name.uri); 1186 attributes.addAttribute(fTempQName, attType, attValue); 1187 } 1188 } 1189 // get next att decl in the Grammar for this element 1190 attlistIndex = fDTDGrammar.getNextAttributeDeclIndex(attlistIndex); 1191 } 1192 1193 // now iterate through the expanded attributes for 1194 // 1. if every attribute seen is declared in the DTD 1195 // 2. check if the VC: default_fixed holds 1196 // 3. validate every attribute. 1197 int attrCount = attributes.getLength(); 1198 for (int i = 0; i < attrCount; i++) { 1199 String attrRawName = attributes.getQName(i); 1200 boolean declared = false; 1201 if (fPerformValidation) { 1202 if (fGrammarBucket.getStandalone()) { 1203 // check VC: Standalone Document Declaration, entities 1204 // references appear in the document. 1205 // REVISIT: this can be combined to a single check in 1206 // startEntity if we add one more argument in 1207 // startEntity, inAttrValue 1208 String nonNormalizedValue = attributes.getNonNormalizedValue(i); 1209 if (nonNormalizedValue != null) { 1210 String entityName = getExternalEntityRefInAttrValue(nonNormalizedValue); 1211 if (entityName != null) { 1212 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1213 "MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE", 1214 new Object[]{entityName}, 1215 XMLErrorReporter.SEVERITY_ERROR); 1216 } 1217 } 1218 } 1219 } 1220 int position = 1221 fDTDGrammar.getFirstAttributeDeclIndex(elementIndex); 1222 while (position != -1) { 1223 fDTDGrammar.getAttributeDecl(position, fTempAttDecl); 1224 if (fTempAttDecl.name.rawname == attrRawName) { 1225 // found the match att decl, 1226 declared = true; 1227 break; 1228 } 1229 position = fDTDGrammar.getNextAttributeDeclIndex(position); 1230 } 1231 if (!declared) { 1232 if (fPerformValidation) { 1233 // REVISIT - cache the elem/attr tuple so that we only 1234 // give this error once for each unique occurrence 1235 Object[] args = { elementName.rawname, attrRawName}; 1236 1237 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1238 "MSG_ATTRIBUTE_NOT_DECLARED", 1239 args,XMLErrorReporter.SEVERITY_ERROR); 1240 } 1241 continue; 1242 } 1243 // attribute is declared 1244 1245 // fTempAttDecl should have the right value set now, so 1246 // the following is not needed 1247 // fGrammar.getAttributeDecl(attDefIndex,fTempAttDecl); 1248 1249 String type = getAttributeTypeName(fTempAttDecl); 1250 attributes.setType(i, type); 1251 attributes.getAugmentations(i).putItem(Constants.ATTRIBUTE_DECLARED, Boolean.TRUE); 1252 1253 boolean changedByNormalization = false; 1254 String oldValue = attributes.getValue(i); 1255 String attrValue = oldValue; 1256 if (attributes.isSpecified(i) && type != XMLSymbols.fCDATASymbol) { 1257 changedByNormalization = normalizeAttrValue(attributes, i); 1258 attrValue = attributes.getValue(i); 1259 if (fPerformValidation && fGrammarBucket.getStandalone() 1260 && changedByNormalization 1261 && fDTDGrammar.getAttributeDeclIsExternal(position) 1262 ) { 1263 // check VC: Standalone Document Declaration 1264 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1265 "MSG_ATTVALUE_CHANGED_DURING_NORMALIZATION_WHEN_STANDALONE", 1266 new Object[]{attrRawName, oldValue, attrValue}, 1267 XMLErrorReporter.SEVERITY_ERROR); 1268 } 1269 } 1270 if (!fPerformValidation) { 1271 continue; 1272 } 1273 if (fTempAttDecl.simpleType.defaultType == 1274 XMLSimpleType.DEFAULT_TYPE_FIXED) { 1275 String defaultValue = fTempAttDecl.simpleType.defaultValue; 1276 1277 if (!attrValue.equals(defaultValue)) { 1278 Object[] args = {elementName.localpart, 1279 attrRawName, 1280 attrValue, 1281 defaultValue}; 1282 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1283 "MSG_FIXED_ATTVALUE_INVALID", 1284 args, XMLErrorReporter.SEVERITY_ERROR); 1285 } 1286 } 1287 1288 if (fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ENTITY || 1289 fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ENUMERATION || 1290 fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_ID || 1291 fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_IDREF || 1292 fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_NMTOKEN || 1293 fTempAttDecl.simpleType.type == XMLSimpleType.TYPE_NOTATION 1294 ) { 1295 validateDTDattribute(elementName, attrValue, fTempAttDecl); 1296 } 1297 } // for all attributes 1298 1299 } // addDTDDefaultAttrsAndValidate(int,XMLAttrList) 1300 1301 /** Checks entities in attribute values for standalone VC. */ getExternalEntityRefInAttrValue(String nonNormalizedValue)1302 protected String getExternalEntityRefInAttrValue(String nonNormalizedValue) { 1303 int valLength = nonNormalizedValue.length(); 1304 int ampIndex = nonNormalizedValue.indexOf('&'); 1305 while (ampIndex != -1) { 1306 if (ampIndex + 1 < valLength && 1307 nonNormalizedValue.charAt(ampIndex+1) != '#') { 1308 int semicolonIndex = nonNormalizedValue.indexOf(';', ampIndex+1); 1309 String entityName = nonNormalizedValue.substring(ampIndex+1, semicolonIndex); 1310 entityName = fSymbolTable.addSymbol(entityName); 1311 int entIndex = fDTDGrammar.getEntityDeclIndex(entityName); 1312 if (entIndex > -1) { 1313 fDTDGrammar.getEntityDecl(entIndex, fEntityDecl); 1314 if (fEntityDecl.inExternal || 1315 (entityName = getExternalEntityRefInAttrValue(fEntityDecl.value)) != null) { 1316 return entityName; 1317 } 1318 } 1319 } 1320 ampIndex = nonNormalizedValue.indexOf('&', ampIndex+1); 1321 } 1322 return null; 1323 } // isExternalEntityRefInAttrValue(String):String 1324 1325 /** 1326 * Validate attributes in DTD fashion. 1327 */ validateDTDattribute(QName element, String attValue, XMLAttributeDecl attributeDecl)1328 protected void validateDTDattribute(QName element, String attValue, 1329 XMLAttributeDecl attributeDecl) 1330 throws XNIException { 1331 1332 switch (attributeDecl.simpleType.type) { 1333 case XMLSimpleType.TYPE_ENTITY: { 1334 // NOTE: Save this information because invalidStandaloneAttDef 1335 boolean isAlistAttribute = attributeDecl.simpleType.list; 1336 1337 try { 1338 if (isAlistAttribute) { 1339 fValENTITIES.validate(attValue, fValidationState); 1340 } 1341 else { 1342 fValENTITY.validate(attValue, fValidationState); 1343 } 1344 } 1345 catch (InvalidDatatypeValueException ex) { 1346 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1347 ex.getKey(), 1348 ex.getArgs(), 1349 XMLErrorReporter.SEVERITY_ERROR ); 1350 1351 } 1352 break; 1353 } 1354 1355 case XMLSimpleType.TYPE_NOTATION: 1356 case XMLSimpleType.TYPE_ENUMERATION: { 1357 boolean found = false; 1358 String [] enumVals = attributeDecl.simpleType.enumeration; 1359 if (enumVals == null) { 1360 found = false; 1361 } 1362 else 1363 for (int i = 0; i < enumVals.length; i++) { 1364 if (attValue == enumVals[i] || attValue.equals(enumVals[i])) { 1365 found = true; 1366 break; 1367 } 1368 } 1369 1370 if (!found) { 1371 StringBuilder enumValueString = new StringBuilder(); 1372 if (enumVals != null) 1373 for (int i = 0; i < enumVals.length; i++) { 1374 enumValueString.append(enumVals[i]+" "); 1375 } 1376 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1377 "MSG_ATTRIBUTE_VALUE_NOT_IN_LIST", 1378 new Object[]{attributeDecl.name.rawname, attValue, enumValueString}, 1379 XMLErrorReporter.SEVERITY_ERROR); 1380 } 1381 break; 1382 } 1383 1384 case XMLSimpleType.TYPE_ID: { 1385 try { 1386 fValID.validate(attValue, fValidationState); 1387 } 1388 catch (InvalidDatatypeValueException ex) { 1389 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1390 ex.getKey(), 1391 ex.getArgs(), 1392 XMLErrorReporter.SEVERITY_ERROR ); 1393 } 1394 break; 1395 } 1396 1397 case XMLSimpleType.TYPE_IDREF: { 1398 boolean isAlistAttribute = attributeDecl.simpleType.list;//Caveat - Save this information because invalidStandaloneAttDef 1399 1400 try { 1401 if (isAlistAttribute) { 1402 fValIDRefs.validate(attValue, fValidationState); 1403 } 1404 else { 1405 fValIDRef.validate(attValue, fValidationState); 1406 } 1407 } 1408 catch (InvalidDatatypeValueException ex) { 1409 if (isAlistAttribute) { 1410 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1411 "IDREFSInvalid", 1412 new Object[]{attValue}, 1413 XMLErrorReporter.SEVERITY_ERROR ); 1414 } 1415 else { 1416 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1417 ex.getKey(), 1418 ex.getArgs(), 1419 XMLErrorReporter.SEVERITY_ERROR ); 1420 } 1421 1422 } 1423 break; 1424 } 1425 1426 case XMLSimpleType.TYPE_NMTOKEN: { 1427 boolean isAlistAttribute = attributeDecl.simpleType.list;//Caveat - Save this information because invalidStandaloneAttDef 1428 //changes fTempAttDef 1429 try { 1430 if (isAlistAttribute) { 1431 fValNMTOKENS.validate(attValue, fValidationState); 1432 } 1433 else { 1434 fValNMTOKEN.validate(attValue, fValidationState); 1435 } 1436 } 1437 catch (InvalidDatatypeValueException ex) { 1438 if (isAlistAttribute) { 1439 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1440 "NMTOKENSInvalid", 1441 new Object[] { attValue}, 1442 XMLErrorReporter.SEVERITY_ERROR); 1443 } 1444 else { 1445 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1446 "NMTOKENInvalid", 1447 new Object[] { attValue}, 1448 XMLErrorReporter.SEVERITY_ERROR); 1449 } 1450 } 1451 break; 1452 } 1453 1454 } // switch 1455 1456 } // validateDTDattribute(QName,String,XMLAttributeDecl) 1457 1458 1459 /** Returns true if invalid standalone attribute definition. */ invalidStandaloneAttDef(QName element, QName attribute)1460 protected boolean invalidStandaloneAttDef(QName element, QName attribute) { 1461 // REVISIT: This obviously needs to be fixed! -Ac 1462 boolean state = true; 1463 /* 1464 if (fStandaloneReader == -1) { 1465 return false; 1466 } 1467 // we are normalizing a default att value... this ok? 1468 if (element.rawname == -1) { 1469 return false; 1470 } 1471 return getAttDefIsExternal(element, attribute); 1472 */ 1473 return state; 1474 } 1475 1476 1477 // 1478 // Private methods 1479 // 1480 1481 1482 /** 1483 * Normalize the attribute value of a non CDATA attributes collapsing 1484 * sequences of space characters (x20) 1485 * 1486 * @param attributes The list of attributes 1487 * @param index The index of the attribute to normalize 1488 */ normalizeAttrValue(XMLAttributes attributes, int index)1489 private boolean normalizeAttrValue(XMLAttributes attributes, int index) { 1490 // vars 1491 boolean leadingSpace = true; 1492 boolean spaceStart = false; 1493 boolean readingNonSpace = false; 1494 int count = 0; 1495 String attrValue = attributes.getValue(index); 1496 char[] attValue = new char[attrValue.length()]; 1497 1498 fBuffer.setLength(0); 1499 attrValue.getChars(0, attrValue.length(), attValue, 0); 1500 for (int i = 0; i < attValue.length; i++) { 1501 1502 if (attValue[i] == ' ') { 1503 1504 // now the tricky part 1505 if (readingNonSpace) { 1506 spaceStart = true; 1507 readingNonSpace = false; 1508 } 1509 1510 if (spaceStart && !leadingSpace) { 1511 spaceStart = false; 1512 fBuffer.append(attValue[i]); 1513 count++; 1514 } 1515 } else { 1516 readingNonSpace = true; 1517 spaceStart = false; 1518 leadingSpace = false; 1519 fBuffer.append(attValue[i]); 1520 count++; 1521 } 1522 } 1523 1524 // check if the last appended character is a space. 1525 if (count > 0 && fBuffer.charAt(count-1) == ' ') { 1526 fBuffer.setLength(count-1); 1527 } 1528 String newValue = fBuffer.toString(); 1529 attributes.setValue(index, newValue); 1530 return ! attrValue.equals(newValue); 1531 } 1532 1533 /** Root element specified. */ rootElementSpecified(QName rootElement)1534 private final void rootElementSpecified(QName rootElement) throws XNIException { 1535 if (fPerformValidation) { 1536 String root1 = fRootElement.rawname; 1537 String root2 = rootElement.rawname; 1538 if (root1 == null || !root1.equals(root2)) { 1539 fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN, 1540 "RootElementTypeMustMatchDoctypedecl", 1541 new Object[]{root1, root2}, 1542 XMLErrorReporter.SEVERITY_ERROR); 1543 } 1544 } 1545 } // rootElementSpecified(QName) 1546 1547 /** 1548 * Check that the content of an element is valid. 1549 * <p> 1550 * This is the method of primary concern to the validator. This method is called 1551 * upon the scanner reaching the end tag of an element. At that time, the 1552 * element's children must be structurally validated, so it calls this method. 1553 * The index of the element being checked (in the decl pool), is provided as 1554 * well as an array of element name indexes of the children. The validator must 1555 * confirm that this element can have these children in this order. 1556 * <p> 1557 * This can also be called to do 'what if' testing of content models just to see 1558 * if they would be valid. 1559 * <p> 1560 * Note that the element index is an index into the element decl pool, whereas 1561 * the children indexes are name indexes, i.e. into the string pool. 1562 * <p> 1563 * A value of -1 in the children array indicates a PCDATA node. All other 1564 * indexes will be positive and represent child elements. The count can be 1565 * zero, since some elements have the EMPTY content model and that must be 1566 * confirmed. 1567 * 1568 * @param elementIndex The index within the <code>ElementDeclPool</code> of this 1569 * element. 1570 * @param childCount The number of entries in the <code>children</code> array. 1571 * @param children The children of this element. 1572 * 1573 * @return The value -1 if fully valid, else the 0 based index of the child 1574 * that first failed. If the value returned is equal to the number 1575 * of children, then additional content is required to reach a valid 1576 * ending state. 1577 * 1578 * @exception Exception Thrown on error. 1579 */ checkContent(int elementIndex, QName[] children, int childOffset, int childCount)1580 private int checkContent(int elementIndex, 1581 QName[] children, 1582 int childOffset, 1583 int childCount) throws XNIException { 1584 1585 fDTDGrammar.getElementDecl(elementIndex, fTempElementDecl); 1586 1587 // Get out the content spec for this element 1588 final int contentType = fCurrentContentSpecType; 1589 1590 1591 // 1592 // Deal with the possible types of content. We try to optimized here 1593 // by dealing specially with content models that don't require the 1594 // full DFA treatment. 1595 // 1596 if (contentType == XMLElementDecl.TYPE_EMPTY) { 1597 // 1598 // If the child count is greater than zero, then this is 1599 // an error right off the bat at index 0. 1600 // 1601 if (childCount != 0) { 1602 return 0; 1603 } 1604 } 1605 else if (contentType == XMLElementDecl.TYPE_ANY) { 1606 // 1607 // This one is open game so we don't pass any judgement on it 1608 // at all. Its assumed to fine since it can hold anything. 1609 // 1610 } 1611 else if (contentType == XMLElementDecl.TYPE_MIXED || 1612 contentType == XMLElementDecl.TYPE_CHILDREN) { 1613 // Get the content model for this element, faulting it in if needed 1614 ContentModelValidator cmElem = null; 1615 cmElem = fTempElementDecl.contentModelValidator; 1616 int result = cmElem.validate(children, childOffset, childCount); 1617 return result; 1618 } 1619 else if (contentType == -1) { 1620 //REVISIT 1621 /**** 1622 reportRecoverableXMLError(XMLMessages.MSG_ELEMENT_NOT_DECLARED, 1623 XMLMessages.VC_ELEMENT_VALID, 1624 elementType); 1625 /****/ 1626 } 1627 else if (contentType == XMLElementDecl.TYPE_SIMPLE) { 1628 1629 //REVISIT 1630 // this should never be reached in the case of DTD validation. 1631 1632 } 1633 else { 1634 //REVISIT 1635 /**** 1636 fErrorReporter.reportError(fErrorReporter.getLocator(), 1637 ImplementationMessages.XERCES_IMPLEMENTATION_DOMAIN, 1638 ImplementationMessages.VAL_CST, 1639 0, 1640 null, 1641 XMLErrorReporter.ERRORTYPE_FATAL_ERROR); 1642 /****/ 1643 } 1644 1645 // We succeeded 1646 return -1; 1647 1648 } // checkContent(int,int,QName[]):int 1649 1650 /** Character data in content. */ charDataInContent()1651 private void charDataInContent() { 1652 1653 if (DEBUG_ELEMENT_CHILDREN) { 1654 System.out.println("charDataInContent()"); 1655 } 1656 if (fElementChildren.length <= fElementChildrenLength) { 1657 QName[] newarray = new QName[fElementChildren.length * 2]; 1658 System.arraycopy(fElementChildren, 0, newarray, 0, fElementChildren.length); 1659 fElementChildren = newarray; 1660 } 1661 QName qname = fElementChildren[fElementChildrenLength]; 1662 if (qname == null) { 1663 for (int i = fElementChildrenLength; i < fElementChildren.length; i++) { 1664 fElementChildren[i] = new QName(); 1665 } 1666 qname = fElementChildren[fElementChildrenLength]; 1667 } 1668 qname.clear(); 1669 fElementChildrenLength++; 1670 1671 } // charDataInCount() 1672 1673 /** convert attribute type from ints to strings */ getAttributeTypeName(XMLAttributeDecl attrDecl)1674 private String getAttributeTypeName(XMLAttributeDecl attrDecl) { 1675 1676 switch (attrDecl.simpleType.type) { 1677 case XMLSimpleType.TYPE_ENTITY: { 1678 return attrDecl.simpleType.list ? XMLSymbols.fENTITIESSymbol : XMLSymbols.fENTITYSymbol; 1679 } 1680 case XMLSimpleType.TYPE_ENUMERATION: { 1681 int totalLength = 2; 1682 for (int i = 0; i < attrDecl.simpleType.enumeration.length; i++) { 1683 totalLength += attrDecl.simpleType.enumeration[i].length() + 1; 1684 } 1685 StringBuilder buffer = new StringBuilder(totalLength); 1686 buffer.append('('); 1687 for (int i=0; i<attrDecl.simpleType.enumeration.length ; i++) { 1688 if (i > 0) { 1689 buffer.append('|'); 1690 } 1691 buffer.append(attrDecl.simpleType.enumeration[i]); 1692 } 1693 buffer.append(')'); 1694 return fSymbolTable.addSymbol(buffer.toString()); 1695 } 1696 case XMLSimpleType.TYPE_ID: { 1697 return XMLSymbols.fIDSymbol; 1698 } 1699 case XMLSimpleType.TYPE_IDREF: { 1700 return attrDecl.simpleType.list ? XMLSymbols.fIDREFSSymbol : XMLSymbols.fIDREFSymbol; 1701 } 1702 case XMLSimpleType.TYPE_NMTOKEN: { 1703 return attrDecl.simpleType.list ? XMLSymbols.fNMTOKENSSymbol : XMLSymbols.fNMTOKENSymbol; 1704 } 1705 case XMLSimpleType.TYPE_NOTATION: { 1706 return XMLSymbols.fNOTATIONSymbol; 1707 } 1708 } 1709 return XMLSymbols.fCDATASymbol; 1710 1711 } // getAttributeTypeName(XMLAttributeDecl):String 1712 1713 /** initialization */ init()1714 protected void init() { 1715 1716 // datatype validators 1717 if (fValidation || fDynamicValidation) { 1718 try { 1719 //REVISIT: datatypeRegistry + initialization of datatype 1720 // why do we cast to ListDatatypeValidator? 1721 fValID = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fIDSymbol); 1722 fValIDRef = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fIDREFSymbol); 1723 fValIDRefs = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fIDREFSSymbol); 1724 fValENTITY = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fENTITYSymbol); 1725 fValENTITIES = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fENTITIESSymbol); 1726 fValNMTOKEN = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fNMTOKENSymbol); 1727 fValNMTOKENS = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fNMTOKENSSymbol); 1728 fValNOTATION = fDatatypeValidatorFactory.getBuiltInDV(XMLSymbols.fNOTATIONSymbol); 1729 1730 } 1731 catch (Exception e) { 1732 // should never happen 1733 e.printStackTrace(System.err); 1734 } 1735 1736 } 1737 1738 } // init() 1739 1740 /** ensure element stack capacity */ ensureStackCapacity(int newElementDepth)1741 private void ensureStackCapacity (int newElementDepth) { 1742 if (newElementDepth == fElementQNamePartsStack.length) { 1743 1744 QName[] newStackOfQueue = new QName[newElementDepth * 2]; 1745 System.arraycopy(this.fElementQNamePartsStack, 0, newStackOfQueue, 0, newElementDepth ); 1746 fElementQNamePartsStack = newStackOfQueue; 1747 1748 QName qname = fElementQNamePartsStack[newElementDepth]; 1749 if (qname == null) { 1750 for (int i = newElementDepth; i < fElementQNamePartsStack.length; i++) { 1751 fElementQNamePartsStack[i] = new QName(); 1752 } 1753 } 1754 1755 int[] newStack = new int[newElementDepth * 2]; 1756 System.arraycopy(fElementIndexStack, 0, newStack, 0, newElementDepth); 1757 fElementIndexStack = newStack; 1758 1759 newStack = new int[newElementDepth * 2]; 1760 System.arraycopy(fContentSpecTypeStack, 0, newStack, 0, newElementDepth); 1761 fContentSpecTypeStack = newStack; 1762 1763 } 1764 } // ensureStackCapacity 1765 1766 1767 // 1768 // Protected methods 1769 // 1770 1771 /** Handle element 1772 * @return true if validator is removed from the pipeline 1773 */ handleStartElement(QName element, XMLAttributes attributes, Augmentations augs)1774 protected boolean handleStartElement(QName element, XMLAttributes attributes, Augmentations augs) 1775 throws XNIException { 1776 1777 1778 // VC: Root Element Type 1779 // see if the root element's name matches the one in DoctypeDecl 1780 if (!fSeenRootElement) { 1781 // REVISIT: Here are current assumptions about validation features 1782 // given that XMLSchema validator is in the pipeline 1783 // 1784 // http://xml.org/sax/features/validation = true 1785 // http://apache.org/xml/features/validation/schema = true 1786 // 1787 // [1] XML instance document only has reference to a DTD 1788 // Outcome: report validation errors only against dtd. 1789 // 1790 // [2] XML instance document has only XML Schema grammars: 1791 // Outcome: report validation errors only against schemas (no errors produced from DTD validator) 1792 // 1793 // [3] XML instance document has DTD and XML schemas: 1794 // [a] if schema language is not set outcome - validation errors reported against both grammars: DTD and schemas. 1795 // [b] if schema language is set to XML Schema - do not report validation errors 1796 // 1797 // if dynamic validation is on 1798 // validate only against grammar we've found (depending on settings 1799 // for schema feature) 1800 // 1801 // 1802 fPerformValidation = validate(); 1803 fSeenRootElement = true; 1804 fValidationManager.setEntityState(fDTDGrammar); 1805 fValidationManager.setGrammarFound(fSeenDoctypeDecl); 1806 rootElementSpecified(element); 1807 } 1808 if (fDTDGrammar == null) { 1809 1810 if (!fPerformValidation) { 1811 fCurrentElementIndex = -1; 1812 fCurrentContentSpecType = -1; 1813 fInElementContent = false; 1814 } 1815 if (fPerformValidation) { 1816 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1817 "MSG_GRAMMAR_NOT_FOUND", 1818 new Object[]{ element.rawname}, 1819 XMLErrorReporter.SEVERITY_ERROR); 1820 } 1821 // modify pipeline 1822 if (fDocumentSource !=null ) { 1823 fDocumentSource.setDocumentHandler(fDocumentHandler); 1824 if (fDocumentHandler != null) 1825 fDocumentHandler.setDocumentSource(fDocumentSource); 1826 return true; 1827 } 1828 } 1829 else { 1830 // resolve the element 1831 fCurrentElementIndex = fDTDGrammar.getElementDeclIndex(element); 1832 //changed here.. new function for getContentSpecType 1833 fCurrentContentSpecType = fDTDGrammar.getContentSpecType(fCurrentElementIndex); 1834 if (fCurrentContentSpecType == -1 && fPerformValidation) { 1835 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1836 "MSG_ELEMENT_NOT_DECLARED", 1837 new Object[]{ element.rawname}, 1838 XMLErrorReporter.SEVERITY_ERROR); 1839 } 1840 1841 // 0. insert default attributes 1842 // 1. normalize the attributes 1843 // 2. validate the attrivute list. 1844 // TO DO: 1845 //changed here.. also pass element name, 1846 addDTDDefaultAttrsAndValidate(element, fCurrentElementIndex, attributes); 1847 } 1848 1849 // set element content state 1850 fInElementContent = fCurrentContentSpecType == XMLElementDecl.TYPE_CHILDREN; 1851 1852 // increment the element depth, add this element's 1853 // QName to its enclosing element 's children list 1854 fElementDepth++; 1855 if (fPerformValidation) { 1856 // push current length onto stack 1857 if (fElementChildrenOffsetStack.length <= fElementDepth) { 1858 int newarray[] = new int[fElementChildrenOffsetStack.length * 2]; 1859 System.arraycopy(fElementChildrenOffsetStack, 0, newarray, 0, fElementChildrenOffsetStack.length); 1860 fElementChildrenOffsetStack = newarray; 1861 } 1862 fElementChildrenOffsetStack[fElementDepth] = fElementChildrenLength; 1863 1864 // add this element to children 1865 if (fElementChildren.length <= fElementChildrenLength) { 1866 QName[] newarray = new QName[fElementChildrenLength * 2]; 1867 System.arraycopy(fElementChildren, 0, newarray, 0, fElementChildren.length); 1868 fElementChildren = newarray; 1869 } 1870 QName qname = fElementChildren[fElementChildrenLength]; 1871 if (qname == null) { 1872 for (int i = fElementChildrenLength; i < fElementChildren.length; i++) { 1873 fElementChildren[i] = new QName(); 1874 } 1875 qname = fElementChildren[fElementChildrenLength]; 1876 } 1877 qname.setValues(element); 1878 fElementChildrenLength++; 1879 } 1880 1881 // save current element information 1882 fCurrentElement.setValues(element); 1883 ensureStackCapacity(fElementDepth); 1884 fElementQNamePartsStack[fElementDepth].setValues(fCurrentElement); 1885 fElementIndexStack[fElementDepth] = fCurrentElementIndex; 1886 fContentSpecTypeStack[fElementDepth] = fCurrentContentSpecType; 1887 startNamespaceScope(element, attributes, augs); 1888 return false; 1889 1890 } // handleStartElement(QName,XMLAttributes) 1891 startNamespaceScope(QName element, XMLAttributes attributes, Augmentations augs)1892 protected void startNamespaceScope(QName element, XMLAttributes attributes, Augmentations augs){ 1893 } 1894 1895 /** Handle end element. */ handleEndElement(QName element, Augmentations augs, boolean isEmpty)1896 protected void handleEndElement(QName element, Augmentations augs, boolean isEmpty) 1897 throws XNIException { 1898 1899 // decrease element depth 1900 fElementDepth--; 1901 1902 // validate 1903 if (fPerformValidation) { 1904 int elementIndex = fCurrentElementIndex; 1905 if (elementIndex != -1 && fCurrentContentSpecType != -1) { 1906 QName children[] = fElementChildren; 1907 int childrenOffset = fElementChildrenOffsetStack[fElementDepth + 1] + 1; 1908 int childrenLength = fElementChildrenLength - childrenOffset; 1909 int result = checkContent(elementIndex, 1910 children, childrenOffset, childrenLength); 1911 1912 if (result != -1) { 1913 fDTDGrammar.getElementDecl(elementIndex, fTempElementDecl); 1914 if (fTempElementDecl.type == XMLElementDecl.TYPE_EMPTY) { 1915 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1916 "MSG_CONTENT_INVALID", 1917 new Object[]{ element.rawname, "EMPTY"}, 1918 XMLErrorReporter.SEVERITY_ERROR); 1919 } 1920 else { 1921 String messageKey = result != childrenLength ? 1922 "MSG_CONTENT_INVALID" : "MSG_CONTENT_INCOMPLETE"; 1923 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1924 messageKey, 1925 new Object[]{ element.rawname, 1926 fDTDGrammar.getContentSpecAsString(elementIndex)}, 1927 XMLErrorReporter.SEVERITY_ERROR); 1928 } 1929 } 1930 } 1931 fElementChildrenLength = fElementChildrenOffsetStack[fElementDepth + 1] + 1; 1932 } 1933 1934 endNamespaceScope(fCurrentElement, augs, isEmpty); 1935 1936 // now pop this element off the top of the element stack 1937 if (fElementDepth < -1) { 1938 throw new RuntimeException("FWK008 Element stack underflow"); 1939 } 1940 if (fElementDepth < 0) { 1941 fCurrentElement.clear(); 1942 fCurrentElementIndex = -1; 1943 fCurrentContentSpecType = -1; 1944 fInElementContent = false; 1945 1946 // TO DO : fix this 1947 // 1948 // Check after document is fully parsed 1949 // (1) check that there was an element with a matching id for every 1950 // IDREF and IDREFS attr (V_IDREF0) 1951 // 1952 if (fPerformValidation) { 1953 Iterator<String> invIdRefs = fValidationState.checkIDRefID(); 1954 if (invIdRefs != null) { 1955 while (invIdRefs.hasNext()) { 1956 fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN, 1957 "MSG_ELEMENT_WITH_ID_REQUIRED", 1958 new Object[]{invIdRefs.next()}, 1959 XMLErrorReporter.SEVERITY_ERROR ); 1960 } 1961 } 1962 } 1963 return; 1964 } 1965 1966 // If Namespace enable then localName != rawName 1967 fCurrentElement.setValues(fElementQNamePartsStack[fElementDepth]); 1968 1969 fCurrentElementIndex = fElementIndexStack[fElementDepth]; 1970 fCurrentContentSpecType = fContentSpecTypeStack[fElementDepth]; 1971 fInElementContent = (fCurrentContentSpecType == XMLElementDecl.TYPE_CHILDREN); 1972 1973 } // handleEndElement(QName,boolean) 1974 endNamespaceScope(QName element, Augmentations augs, boolean isEmpty)1975 protected void endNamespaceScope(QName element, Augmentations augs, boolean isEmpty){ 1976 1977 // call handlers 1978 if (fDocumentHandler != null && !isEmpty) { 1979 // NOTE: The binding of the element doesn't actually happen 1980 // yet because the namespace binder does that. However, 1981 // if it does it before this point, then the endPrefix- 1982 // Mapping calls get made too soon! As long as the 1983 // rawnames match, we know it'll have a good binding, 1984 // so we can just use the current element. -Ac 1985 fDocumentHandler.endElement(fCurrentElement, augs); 1986 } 1987 } 1988 1989 // returns whether a character is space according to the 1990 // version of XML this validator supports. isSpace(int c)1991 protected boolean isSpace(int c) { 1992 return XMLChar.isSpace(c); 1993 } // isSpace(int): boolean 1994 characterData(String data, Augmentations augs)1995 public boolean characterData(String data, Augmentations augs) { 1996 characters(new XMLString(data.toCharArray(), 0, data.length()), augs); 1997 return true; 1998 } 1999 2000 } // class XMLDTDValidator 2001