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