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.XMLErrorReporter; 26 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter; 27 import com.sun.org.apache.xerces.internal.util.SymbolTable; 28 import com.sun.org.apache.xerces.internal.util.XMLChar; 29 import com.sun.org.apache.xerces.internal.util.XMLSymbols; 30 import com.sun.org.apache.xerces.internal.xni.Augmentations; 31 import com.sun.org.apache.xerces.internal.xni.XMLDTDContentModelHandler; 32 import com.sun.org.apache.xerces.internal.xni.XMLDTDHandler; 33 import com.sun.org.apache.xerces.internal.xni.XMLLocator; 34 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier; 35 import com.sun.org.apache.xerces.internal.xni.XMLString; 36 import com.sun.org.apache.xerces.internal.xni.XNIException; 37 import com.sun.org.apache.xerces.internal.xni.grammars.Grammar; 38 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarDescription; 39 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool; 40 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent; 41 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager; 42 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; 43 import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDContentModelFilter; 44 import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDContentModelSource; 45 import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDFilter; 46 import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDSource; 47 import java.util.ArrayList; 48 import java.util.HashMap; 49 import java.util.List; 50 import java.util.Locale; 51 import java.util.Map; 52 import java.util.StringTokenizer; 53 54 /** 55 * The DTD processor. The processor implements a DTD 56 * filter: receiving DTD events from the DTD scanner; validating 57 * the content and structure; building a grammar, if applicable; 58 * and notifying the DTDHandler of the information resulting from the 59 * process. 60 * <p> 61 * This component requires the following features and properties from the 62 * component manager that uses it: 63 * <ul> 64 * <li>http://xml.org/sax/features/namespaces</li> 65 * <li>http://apache.org/xml/properties/internal/symbol-table</li> 66 * <li>http://apache.org/xml/properties/internal/error-reporter</li> 67 * <li>http://apache.org/xml/properties/internal/grammar-pool</li> 68 * <li>http://apache.org/xml/properties/internal/datatype-validator-factory</li> 69 * </ul> 70 * 71 * @xerces.internal 72 * 73 * @author Neil Graham, IBM 74 * 75 */ 76 public class XMLDTDProcessor 77 implements XMLComponent, XMLDTDFilter, XMLDTDContentModelFilter { 78 79 // 80 // Constants 81 // 82 83 /** Top level scope (-1). */ 84 private static final int TOP_LEVEL_SCOPE = -1; 85 86 // feature identifiers 87 88 /** Feature identifier: validation. */ 89 protected static final String VALIDATION = 90 Constants.SAX_FEATURE_PREFIX + Constants.VALIDATION_FEATURE; 91 92 /** Feature identifier: notify character references. */ 93 protected static final String NOTIFY_CHAR_REFS = 94 Constants.XERCES_FEATURE_PREFIX + Constants.NOTIFY_CHAR_REFS_FEATURE; 95 96 /** Feature identifier: warn on duplicate attdef */ 97 protected static final String WARN_ON_DUPLICATE_ATTDEF = 98 Constants.XERCES_FEATURE_PREFIX +Constants.WARN_ON_DUPLICATE_ATTDEF_FEATURE; 99 100 /** Feature identifier: warn on undeclared element referenced in content model. */ 101 protected static final String WARN_ON_UNDECLARED_ELEMDEF = 102 Constants.XERCES_FEATURE_PREFIX + Constants.WARN_ON_UNDECLARED_ELEMDEF_FEATURE; 103 104 protected static final String PARSER_SETTINGS = 105 Constants.XERCES_FEATURE_PREFIX + Constants.PARSER_SETTINGS; 106 107 // property identifiers 108 109 /** Property identifier: symbol table. */ 110 protected static final String SYMBOL_TABLE = 111 Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; 112 113 /** Property identifier: error reporter. */ 114 protected static final String ERROR_REPORTER = 115 Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY; 116 117 /** Property identifier: grammar pool. */ 118 protected static final String GRAMMAR_POOL = 119 Constants.XERCES_PROPERTY_PREFIX + Constants.XMLGRAMMAR_POOL_PROPERTY; 120 121 /** Property identifier: validator . */ 122 protected static final String DTD_VALIDATOR = 123 Constants.XERCES_PROPERTY_PREFIX + Constants.DTD_VALIDATOR_PROPERTY; 124 125 // recognized features and properties 126 127 /** Recognized features. */ 128 private static final String[] RECOGNIZED_FEATURES = { 129 VALIDATION, 130 WARN_ON_DUPLICATE_ATTDEF, 131 WARN_ON_UNDECLARED_ELEMDEF, 132 NOTIFY_CHAR_REFS, 133 }; 134 135 /** Feature defaults. */ 136 private static final Boolean[] FEATURE_DEFAULTS = { 137 null, 138 Boolean.FALSE, 139 Boolean.FALSE, 140 null, 141 }; 142 143 /** Recognized properties. */ 144 private static final String[] RECOGNIZED_PROPERTIES = { 145 SYMBOL_TABLE, 146 ERROR_REPORTER, 147 GRAMMAR_POOL, 148 DTD_VALIDATOR, 149 }; 150 151 /** Property defaults. */ 152 private static final Object[] PROPERTY_DEFAULTS = { 153 null, 154 null, 155 null, 156 null, 157 }; 158 159 // debugging 160 161 // 162 // Data 163 // 164 165 // features 166 167 /** Validation. */ 168 protected boolean fValidation; 169 170 /** Validation against only DTD */ 171 protected boolean fDTDValidation; 172 173 /** warn on duplicate attribute definition, this feature works only when validation is true */ 174 protected boolean fWarnDuplicateAttdef; 175 176 /** warn on undeclared element referenced in content model, this feature only works when valiation is true */ 177 protected boolean fWarnOnUndeclaredElemdef; 178 179 // properties 180 181 /** Symbol table. */ 182 protected SymbolTable fSymbolTable; 183 184 /** Error reporter. */ 185 protected XMLErrorReporter fErrorReporter; 186 187 /** Grammar bucket. */ 188 protected DTDGrammarBucket fGrammarBucket; 189 190 // the validator to which we look for our grammar bucket (the 191 // validator needs to hold the bucket so that it can initialize 192 // the grammar with details like whether it's for a standalone document... 193 protected XMLDTDValidator fValidator; 194 195 // the grammar pool we'll try to add the grammar to: 196 protected XMLGrammarPool fGrammarPool; 197 198 // what's our Locale? 199 protected Locale fLocale; 200 201 // handlers 202 203 /** DTD handler. */ 204 protected XMLDTDHandler fDTDHandler; 205 206 /** DTD source. */ 207 protected XMLDTDSource fDTDSource; 208 209 /** DTD content model handler. */ 210 protected XMLDTDContentModelHandler fDTDContentModelHandler; 211 212 /** DTD content model source. */ 213 protected XMLDTDContentModelSource fDTDContentModelSource; 214 215 // grammars 216 217 /** DTD Grammar. */ 218 protected DTDGrammar fDTDGrammar; 219 220 // state 221 222 /** Perform validation. */ 223 private boolean fPerformValidation; 224 225 /** True if in an ignore conditional section of the DTD. */ 226 protected boolean fInDTDIgnore; 227 228 // information regarding the current element 229 230 // validation states 231 232 /** Mixed. */ 233 private boolean fMixed; 234 235 // temporary variables 236 237 /** Temporary entity declaration. */ 238 private final XMLEntityDecl fEntityDecl = new XMLEntityDecl(); 239 240 /** Notation declaration hash. */ 241 private final Map<String, String> fNDataDeclNotations = new HashMap<>(); 242 243 /** DTD element declaration name. */ 244 private String fDTDElementDeclName = null; 245 246 /** Mixed element type "hash". */ 247 private final List<String> fMixedElementTypes = new ArrayList<>(); 248 249 /** Element declarations in DTD. */ 250 private final List<String> fDTDElementDecls = new ArrayList<>(); 251 252 // to check for duplicate ID or ANNOTATION attribute declare in 253 // ATTLIST, and misc VCs 254 255 /** ID attribute names. */ 256 private Map<String, String> fTableOfIDAttributeNames; 257 258 /** NOTATION attribute names. */ 259 private Map<String, String> fTableOfNOTATIONAttributeNames; 260 261 /** NOTATION enumeration values. */ 262 private Map<String, String> fNotationEnumVals; 263 264 // 265 // Constructors 266 // 267 268 /** Default constructor. */ 269 public XMLDTDProcessor() { 270 271 // initialize data 272 273 } // <init>() 274 275 // 276 // XMLComponent methods 277 // 278 279 /* 280 * Resets the component. The component can query the component manager 281 * about any features and properties that affect the operation of the 282 * component. 283 * 284 * @param componentManager The component manager. 285 * 286 * @throws SAXException Thrown by component on finitialization error. 287 * For example, if a feature or property is 288 * required for the operation of the component, the 289 * component manager may throw a 290 * SAXNotRecognizedException or a 291 * SAXNotSupportedException. 292 */ 293 public void reset(XMLComponentManager componentManager) throws XMLConfigurationException { 294 295 boolean parser_settings = componentManager.getFeature(PARSER_SETTINGS, true); 296 297 if (!parser_settings) { 298 // parser settings have not been changed 299 reset(); 300 return; 301 } 302 303 // sax features 304 fValidation = componentManager.getFeature(VALIDATION, false); 305 306 fDTDValidation = 307 !(componentManager 308 .getFeature( 309 Constants.XERCES_FEATURE_PREFIX + Constants.SCHEMA_VALIDATION_FEATURE, false)); 310 311 // Xerces features 312 313 fWarnDuplicateAttdef = componentManager.getFeature(WARN_ON_DUPLICATE_ATTDEF, false); 314 fWarnOnUndeclaredElemdef = componentManager.getFeature(WARN_ON_UNDECLARED_ELEMDEF, false); 315 316 // get needed components 317 fErrorReporter = 318 (XMLErrorReporter) componentManager.getProperty( 319 Constants.XERCES_PROPERTY_PREFIX + Constants.ERROR_REPORTER_PROPERTY); 320 fSymbolTable = 321 (SymbolTable) componentManager.getProperty( 322 Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY); 323 324 fGrammarPool = (XMLGrammarPool) componentManager.getProperty(GRAMMAR_POOL, null); 325 326 try { 327 fValidator = (XMLDTDValidator) componentManager.getProperty(DTD_VALIDATOR, null); 328 } catch (ClassCastException e) { 329 fValidator = null; 330 } 331 // we get our grammarBucket from the validator... 332 if (fValidator != null) { 333 fGrammarBucket = fValidator.getGrammarBucket(); 334 } else { 335 fGrammarBucket = null; 336 } 337 reset(); 338 339 } // reset(XMLComponentManager) 340 341 protected void reset() { 342 // clear grammars 343 fDTDGrammar = null; 344 // initialize state 345 fInDTDIgnore = false; 346 347 fNDataDeclNotations.clear(); 348 349 // datatype validators 350 if (fValidation) { 351 352 if (fNotationEnumVals == null) { 353 fNotationEnumVals = new HashMap<>(); 354 } 355 fNotationEnumVals.clear(); 356 357 fTableOfIDAttributeNames = new HashMap<>(); 358 fTableOfNOTATIONAttributeNames = new HashMap<>(); 359 } 360 361 } 362 /** 363 * Returns a list of feature identifiers that are recognized by 364 * this component. This method may return null if no features 365 * are recognized by this component. 366 */ 367 public String[] getRecognizedFeatures() { 368 return RECOGNIZED_FEATURES.clone(); 369 } // getRecognizedFeatures():String[] 370 371 /** 372 * Sets the state of a feature. This method is called by the component 373 * manager any time after reset when a feature changes state. 374 * <p> 375 * <strong>Note:</strong> Components should silently ignore features 376 * that do not affect the operation of the component. 377 * 378 * @param featureId The feature identifier. 379 * @param state The state of the feature. 380 * 381 * @throws SAXNotRecognizedException The component should not throw 382 * this exception. 383 * @throws SAXNotSupportedException The component should not throw 384 * this exception. 385 */ 386 public void setFeature(String featureId, boolean state) 387 throws XMLConfigurationException { 388 } // setFeature(String,boolean) 389 390 /** 391 * Returns a list of property identifiers that are recognized by 392 * this component. This method may return null if no properties 393 * are recognized by this component. 394 */ 395 public String[] getRecognizedProperties() { 396 return RECOGNIZED_PROPERTIES.clone(); 397 } // getRecognizedProperties():String[] 398 399 /** 400 * Sets the value of a property. This method is called by the component 401 * manager any time after reset when a property changes value. 402 * <p> 403 * <strong>Note:</strong> Components should silently ignore properties 404 * that do not affect the operation of the component. 405 * 406 * @param propertyId The property identifier. 407 * @param value The value of the property. 408 * 409 * @throws SAXNotRecognizedException The component should not throw 410 * this exception. 411 * @throws SAXNotSupportedException The component should not throw 412 * this exception. 413 */ 414 public void setProperty(String propertyId, Object value) 415 throws XMLConfigurationException { 416 } // setProperty(String,Object) 417 418 /** 419 * Returns the default state for a feature, or null if this 420 * component does not want to report a default value for this 421 * feature. 422 * 423 * @param featureId The feature identifier. 424 * 425 * @since Xerces 2.2.0 426 */ 427 public Boolean getFeatureDefault(String featureId) { 428 for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { 429 if (RECOGNIZED_FEATURES[i].equals(featureId)) { 430 return FEATURE_DEFAULTS[i]; 431 } 432 } 433 return null; 434 } // getFeatureDefault(String):Boolean 435 436 /** 437 * Returns the default state for a property, or null if this 438 * component does not want to report a default value for this 439 * property. 440 * 441 * @param propertyId The property identifier. 442 * 443 * @since Xerces 2.2.0 444 */ 445 public Object getPropertyDefault(String propertyId) { 446 for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { 447 if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { 448 return PROPERTY_DEFAULTS[i]; 449 } 450 } 451 return null; 452 } // getPropertyDefault(String):Object 453 454 // 455 // XMLDTDSource methods 456 // 457 458 /** 459 * Sets the DTD handler. 460 * 461 * @param dtdHandler The DTD handler. 462 */ 463 public void setDTDHandler(XMLDTDHandler dtdHandler) { 464 fDTDHandler = dtdHandler; 465 } // setDTDHandler(XMLDTDHandler) 466 467 /** 468 * Returns the DTD handler. 469 * 470 * @return The DTD handler. 471 */ 472 public XMLDTDHandler getDTDHandler() { 473 return fDTDHandler; 474 } // getDTDHandler(): XMLDTDHandler 475 476 // 477 // XMLDTDContentModelSource methods 478 // 479 480 /** 481 * Sets the DTD content model handler. 482 * 483 * @param dtdContentModelHandler The DTD content model handler. 484 */ 485 public void setDTDContentModelHandler(XMLDTDContentModelHandler dtdContentModelHandler) { 486 fDTDContentModelHandler = dtdContentModelHandler; 487 } // setDTDContentModelHandler(XMLDTDContentModelHandler) 488 489 /** 490 * Gets the DTD content model handler. 491 * 492 * @return dtdContentModelHandler The DTD content model handler. 493 */ 494 public XMLDTDContentModelHandler getDTDContentModelHandler() { 495 return fDTDContentModelHandler; 496 } // getDTDContentModelHandler(): XMLDTDContentModelHandler 497 498 // 499 // XMLDTDContentModelHandler and XMLDTDHandler methods 500 // 501 502 /** 503 * The start of the DTD external subset. 504 * 505 * @param augs Additional information that may include infoset 506 * augmentations. 507 * 508 * @throws XNIException Thrown by handler to signal an error. 509 */ 510 public void startExternalSubset(XMLResourceIdentifier identifier, 511 Augmentations augs) throws XNIException { 512 if(fDTDGrammar != null) 513 fDTDGrammar.startExternalSubset(identifier, augs); 514 if(fDTDHandler != null){ 515 fDTDHandler.startExternalSubset(identifier, augs); 516 } 517 } 518 519 /** 520 * The end of the DTD external subset. 521 * 522 * @param augs Additional information that may include infoset 523 * augmentations. 524 * 525 * @throws XNIException Thrown by handler to signal an error. 526 */ 527 public void endExternalSubset(Augmentations augs) throws XNIException { 528 if(fDTDGrammar != null) 529 fDTDGrammar.endExternalSubset(augs); 530 if(fDTDHandler != null){ 531 fDTDHandler.endExternalSubset(augs); 532 } 533 } 534 535 /** 536 * Check standalone entity reference. 537 * Made static to make common between the validator and loader. 538 * 539 * @param name 540 *@param grammar grammar to which entity belongs 541 * @param tempEntityDecl empty entity declaration to put results in 542 * @param errorReporter error reporter to send errors to 543 * 544 * @throws XNIException Thrown by application to signal an error. 545 */ 546 protected static void checkStandaloneEntityRef(String name, DTDGrammar grammar, 547 XMLEntityDecl tempEntityDecl, XMLErrorReporter errorReporter) throws XNIException { 548 // check VC: Standalone Document Declartion, entities references appear in the document. 549 int entIndex = grammar.getEntityDeclIndex(name); 550 if (entIndex > -1) { 551 grammar.getEntityDecl(entIndex, tempEntityDecl); 552 if (tempEntityDecl.inExternal) { 553 errorReporter.reportError( XMLMessageFormatter.XML_DOMAIN, 554 "MSG_REFERENCE_TO_EXTERNALLY_DECLARED_ENTITY_WHEN_STANDALONE", 555 new Object[]{name}, XMLErrorReporter.SEVERITY_ERROR); 556 } 557 } 558 } 559 560 /** 561 * A comment. 562 * 563 * @param text The text in the comment. 564 * @param augs Additional information that may include infoset augmentations 565 * 566 * @throws XNIException Thrown by application to signal an error. 567 */ 568 public void comment(XMLString text, Augmentations augs) throws XNIException { 569 570 // call handlers 571 if(fDTDGrammar != null) 572 fDTDGrammar.comment(text, augs); 573 if (fDTDHandler != null) { 574 fDTDHandler.comment(text, augs); 575 } 576 577 } // comment(XMLString) 578 579 580 /** 581 * A processing instruction. Processing instructions consist of a 582 * target name and, optionally, text data. The data is only meaningful 583 * to the application. 584 * <p> 585 * Typically, a processing instruction's data will contain a series 586 * of pseudo-attributes. These pseudo-attributes follow the form of 587 * element attributes but are <strong>not</strong> parsed or presented 588 * to the application as anything other than text. The application is 589 * responsible for parsing the data. 590 * 591 * @param target The target. 592 * @param data The data or null if none specified. 593 * @param augs Additional information that may include infoset augmentations 594 * 595 * @throws XNIException Thrown by handler to signal an error. 596 */ 597 public void processingInstruction(String target, XMLString data, Augmentations augs) 598 throws XNIException { 599 600 // call handlers 601 if(fDTDGrammar != null) 602 fDTDGrammar.processingInstruction(target, data, augs); 603 if (fDTDHandler != null) { 604 fDTDHandler.processingInstruction(target, data, augs); 605 } 606 } // processingInstruction(String,XMLString) 607 608 // 609 // XMLDTDHandler methods 610 // 611 612 /** 613 * The start of the DTD. 614 * 615 * @param locator The document locator, or null if the document 616 * location cannot be reported during the parsing of 617 * the document DTD. However, it is <em>strongly</em> 618 * recommended that a locator be supplied that can 619 * at least report the base system identifier of the 620 * DTD. 621 * @param augs Additional information that may include infoset 622 * augmentations. 623 * 624 * @throws XNIException Thrown by handler to signal an error. 625 */ 626 public void startDTD(XMLLocator locator, Augmentations augs) throws XNIException { 627 628 629 // initialize state 630 fNDataDeclNotations.clear(); 631 fDTDElementDecls.clear(); 632 633 // the grammar bucket's DTDGrammar will now be the 634 // one we want, whether we're constructing it or not. 635 // if we're not constructing it, then we should not have a reference 636 // to it! 637 if( !fGrammarBucket.getActiveGrammar().isImmutable()) { 638 fDTDGrammar = fGrammarBucket.getActiveGrammar(); 639 } 640 641 // call handlers 642 if(fDTDGrammar != null ) 643 fDTDGrammar.startDTD(locator, augs); 644 if (fDTDHandler != null) { 645 fDTDHandler.startDTD(locator, augs); 646 } 647 648 } // startDTD(XMLLocator) 649 650 /** 651 * Characters within an IGNORE conditional section. 652 * 653 * @param text The ignored text. 654 * @param augs Additional information that may include infoset 655 * augmentations. 656 * 657 * @throws XNIException Thrown by handler to signal an error. 658 */ 659 public void ignoredCharacters(XMLString text, Augmentations augs) throws XNIException { 660 661 // ignored characters in DTD 662 if(fDTDGrammar != null ) 663 fDTDGrammar.ignoredCharacters(text, augs); 664 if (fDTDHandler != null) { 665 fDTDHandler.ignoredCharacters(text, augs); 666 } 667 } 668 669 /** 670 * Notifies of the presence of a TextDecl line in an entity. If present, 671 * this method will be called immediately following the startParameterEntity call. 672 * <p> 673 * <strong>Note:</strong> This method is only called for external 674 * parameter entities referenced in the DTD. 675 * 676 * @param version The XML version, or null if not specified. 677 * @param encoding The IANA encoding name of the entity. 678 * @param augs Additional information that may include infoset 679 * augmentations. 680 * 681 * @throws XNIException Thrown by handler to signal an error. 682 */ 683 public void textDecl(String version, String encoding, Augmentations augs) throws XNIException { 684 685 // call handlers 686 if(fDTDGrammar != null ) 687 fDTDGrammar.textDecl(version, encoding, augs); 688 if (fDTDHandler != null) { 689 fDTDHandler.textDecl(version, encoding, augs); 690 } 691 } 692 693 /** 694 * This method notifies of the start of a parameter entity. The parameter 695 * entity name start with a '%' character. 696 * 697 * @param name The name of the parameter entity. 698 * @param identifier The resource identifier. 699 * @param encoding The auto-detected IANA encoding name of the entity 700 * stream. This value will be null in those situations 701 * where the entity encoding is not auto-detected (e.g. 702 * internal parameter entities). 703 * @param augs Additional information that may include infoset 704 * augmentations. 705 * 706 * @throws XNIException Thrown by handler to signal an error. 707 */ 708 public void startParameterEntity(String name, 709 XMLResourceIdentifier identifier, 710 String encoding, 711 Augmentations augs) throws XNIException { 712 713 if (fPerformValidation && fDTDGrammar != null && 714 fGrammarBucket.getStandalone()) { 715 checkStandaloneEntityRef(name, fDTDGrammar, fEntityDecl, fErrorReporter); 716 } 717 // call handlers 718 if(fDTDGrammar != null ) 719 fDTDGrammar.startParameterEntity(name, identifier, encoding, augs); 720 if (fDTDHandler != null) { 721 fDTDHandler.startParameterEntity(name, identifier, encoding, augs); 722 } 723 } 724 725 /** 726 * This method notifies the end of a parameter entity. Parameter entity 727 * names begin with a '%' character. 728 * 729 * @param name The name of the parameter entity. 730 * @param augs Additional information that may include infoset 731 * augmentations. 732 * 733 * @throws XNIException Thrown by handler to signal an error. 734 */ 735 public void endParameterEntity(String name, Augmentations augs) throws XNIException { 736 737 // call handlers 738 if(fDTDGrammar != null ) 739 fDTDGrammar.endParameterEntity(name, augs); 740 if (fDTDHandler != null) { 741 fDTDHandler.endParameterEntity(name, augs); 742 } 743 } 744 745 /** 746 * An element declaration. 747 * 748 * @param name The name of the element. 749 * @param contentModel The element content model. 750 * @param augs Additional information that may include infoset 751 * augmentations. 752 * 753 * @throws XNIException Thrown by handler to signal an error. 754 */ 755 public void elementDecl(String name, String contentModel, Augmentations augs) 756 throws XNIException { 757 758 //check VC: Unique Element Declaration 759 if (fValidation) { 760 if (fDTDElementDecls.contains(name)) { 761 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 762 "MSG_ELEMENT_ALREADY_DECLARED", 763 new Object[]{ name}, 764 XMLErrorReporter.SEVERITY_ERROR); 765 } 766 else { 767 fDTDElementDecls.add(name); 768 } 769 } 770 771 // call handlers 772 if(fDTDGrammar != null ) 773 fDTDGrammar.elementDecl(name, contentModel, augs); 774 if (fDTDHandler != null) { 775 fDTDHandler.elementDecl(name, contentModel, augs); 776 } 777 778 } // elementDecl(String,String) 779 780 /** 781 * The start of an attribute list. 782 * 783 * @param elementName The name of the element that this attribute 784 * list is associated with. 785 * @param augs Additional information that may include infoset 786 * augmentations. 787 * 788 * @throws XNIException Thrown by handler to signal an error. 789 */ 790 public void startAttlist(String elementName, Augmentations augs) 791 throws XNIException { 792 793 // call handlers 794 if(fDTDGrammar != null ) 795 fDTDGrammar.startAttlist(elementName, augs); 796 if (fDTDHandler != null) { 797 fDTDHandler.startAttlist(elementName, augs); 798 } 799 800 } // startAttlist(String) 801 802 /** 803 * An attribute declaration. 804 * 805 * @param elementName The name of the element that this attribute 806 * is associated with. 807 * @param attributeName The name of the attribute. 808 * @param type The attribute type. This value will be one of 809 * the following: "CDATA", "ENTITY", "ENTITIES", 810 * "ENUMERATION", "ID", "IDREF", "IDREFS", 811 * "NMTOKEN", "NMTOKENS", or "NOTATION". 812 * @param enumeration If the type has the value "ENUMERATION" or 813 * "NOTATION", this array holds the allowed attribute 814 * values; otherwise, this array is null. 815 * @param defaultType The attribute default type. This value will be 816 * one of the following: "#FIXED", "#IMPLIED", 817 * "#REQUIRED", or null. 818 * @param defaultValue The attribute default value, or null if no 819 * default value is specified. 820 * @param nonNormalizedDefaultValue The attribute default value with no normalization 821 * performed, or null if no default value is specified. 822 * @param augs Additional information that may include infoset 823 * augmentations. 824 * 825 * @throws XNIException Thrown by handler to signal an error. 826 */ 827 public void attributeDecl(String elementName, String attributeName, 828 String type, String[] enumeration, 829 String defaultType, XMLString defaultValue, 830 XMLString nonNormalizedDefaultValue, Augmentations augs) throws XNIException { 831 832 if (type != XMLSymbols.fCDATASymbol && defaultValue != null) { 833 normalizeDefaultAttrValue(defaultValue); 834 } 835 836 if (fValidation) { 837 838 boolean duplicateAttributeDef = false ; 839 840 //Get Grammar index to grammar array 841 DTDGrammar grammar = (fDTDGrammar != null? fDTDGrammar:fGrammarBucket.getActiveGrammar()); 842 int elementIndex = grammar.getElementDeclIndex( elementName); 843 if (grammar.getAttributeDeclIndex(elementIndex, attributeName) != -1) { 844 //more than one attribute definition is provided for the same attribute of a given element type. 845 duplicateAttributeDef = true ; 846 847 //this feature works only when validation is true. 848 if(fWarnDuplicateAttdef){ 849 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 850 "MSG_DUPLICATE_ATTRIBUTE_DEFINITION", 851 new Object[]{ elementName, attributeName }, 852 XMLErrorReporter.SEVERITY_WARNING ); 853 } 854 } 855 856 857 // 858 // a) VC: One ID per Element Type, If duplicate ID attribute 859 // b) VC: ID attribute Default. if there is a declareared attribute 860 // default for ID it should be of type #IMPLIED or #REQUIRED 861 if (type == XMLSymbols.fIDSymbol) { 862 if (defaultValue != null && defaultValue.length != 0) { 863 if (defaultType == null || 864 !(defaultType == XMLSymbols.fIMPLIEDSymbol || 865 defaultType == XMLSymbols.fREQUIREDSymbol)) { 866 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 867 "IDDefaultTypeInvalid", 868 new Object[]{ attributeName}, 869 XMLErrorReporter.SEVERITY_ERROR); 870 } 871 } 872 873 if (!fTableOfIDAttributeNames.containsKey(elementName)) { 874 fTableOfIDAttributeNames.put(elementName, attributeName); 875 } 876 else { 877 //we should not report an error, when there is duplicate attribute definition for given element type 878 //according to XML 1.0 spec, When more than one definition is provided for the same attribute of a given 879 //element type, the first declaration is binding and later declaration are *ignored*. So processor should 880 //ignore the second declarations, however an application would be warned of the duplicate attribute defintion 881 // if http://apache.org/xml/features/validation/warn-on-duplicate-attdef feature is set to true, 882 // one typical case where this could be a problem, when any XML file 883 // provide the ID type information through internal subset so that it is available to the parser which read 884 //only internal subset. Now that attribute declaration(ID Type) can again be part of external parsed entity 885 //referenced. At that time if parser doesn't make this distinction it will throw an error for VC One ID per 886 //Element Type, which (second defintion) actually should be ignored. Application behavior may differ on the 887 //basis of error or warning thrown. - nb. 888 889 if(!duplicateAttributeDef){ 890 String previousIDAttributeName = fTableOfIDAttributeNames.get( elementName );//rule a) 891 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 892 "MSG_MORE_THAN_ONE_ID_ATTRIBUTE", 893 new Object[]{ elementName, previousIDAttributeName, attributeName}, 894 XMLErrorReporter.SEVERITY_ERROR); 895 } 896 } 897 } 898 899 // 900 // VC: One Notation Per Element Type, should check if there is a 901 // duplicate NOTATION attribute 902 903 if (type == XMLSymbols.fNOTATIONSymbol) { 904 // VC: Notation Attributes: all notation names in the 905 // (attribute) declaration must be declared. 906 for (int i=0; i<enumeration.length; i++) { 907 fNotationEnumVals.put(enumeration[i], attributeName); 908 } 909 910 if (fTableOfNOTATIONAttributeNames.containsKey( elementName ) == false) { 911 fTableOfNOTATIONAttributeNames.put( elementName, attributeName); 912 } 913 else { 914 //we should not report an error, when there is duplicate attribute definition for given element type 915 //according to XML 1.0 spec, When more than one definition is provided for the same attribute of a given 916 //element type, the first declaration is binding and later declaration are *ignored*. So processor should 917 //ignore the second declarations, however an application would be warned of the duplicate attribute definition 918 // if http://apache.org/xml/features/validation/warn-on-duplicate-attdef feature is set to true, 919 // Application behavior may differ on the basis of error or warning thrown. - nb. 920 921 if(!duplicateAttributeDef){ 922 923 String previousNOTATIONAttributeName = fTableOfNOTATIONAttributeNames.get( elementName ); 924 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 925 "MSG_MORE_THAN_ONE_NOTATION_ATTRIBUTE", 926 new Object[]{ elementName, previousNOTATIONAttributeName, attributeName}, 927 XMLErrorReporter.SEVERITY_ERROR); 928 } 929 } 930 } 931 932 // VC: No Duplicate Tokens 933 // XML 1.0 SE Errata - E2 934 if (type == XMLSymbols.fENUMERATIONSymbol || type == XMLSymbols.fNOTATIONSymbol) { 935 outer: 936 for (int i = 0; i < enumeration.length; ++i) { 937 for (int j = i + 1; j < enumeration.length; ++j) { 938 if (enumeration[i].equals(enumeration[j])) { 939 // Only report the first uniqueness violation. There could be others, 940 // but additional overhead would be incurred tracking unique tokens 941 // that have already been encountered. -- mrglavas 942 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 943 type == XMLSymbols.fENUMERATIONSymbol 944 ? "MSG_DISTINCT_TOKENS_IN_ENUMERATION" 945 : "MSG_DISTINCT_NOTATION_IN_ENUMERATION", 946 new Object[]{ elementName, enumeration[i], attributeName }, 947 XMLErrorReporter.SEVERITY_ERROR); 948 break outer; 949 } 950 } 951 } 952 } 953 954 // VC: Attribute Default Legal 955 boolean ok = true; 956 if (defaultValue != null && 957 (defaultType == null || 958 (defaultType != null && defaultType == XMLSymbols.fFIXEDSymbol))) { 959 960 String value = defaultValue.toString(); 961 if (type == XMLSymbols.fNMTOKENSSymbol || 962 type == XMLSymbols.fENTITIESSymbol || 963 type == XMLSymbols.fIDREFSSymbol) { 964 965 StringTokenizer tokenizer = new StringTokenizer(value," "); 966 if (tokenizer.hasMoreTokens()) { 967 while (true) { 968 String nmtoken = tokenizer.nextToken(); 969 if (type == XMLSymbols.fNMTOKENSSymbol) { 970 if (!isValidNmtoken(nmtoken)) { 971 ok = false; 972 break; 973 } 974 } 975 else if (type == XMLSymbols.fENTITIESSymbol || 976 type == XMLSymbols.fIDREFSSymbol) { 977 if (!isValidName(nmtoken)) { 978 ok = false; 979 break; 980 } 981 } 982 if (!tokenizer.hasMoreTokens()) { 983 break; 984 } 985 } 986 } 987 988 } 989 else { 990 if (type == XMLSymbols.fENTITYSymbol || 991 type == XMLSymbols.fIDSymbol || 992 type == XMLSymbols.fIDREFSymbol || 993 type == XMLSymbols.fNOTATIONSymbol) { 994 995 if (!isValidName(value)) { 996 ok = false; 997 } 998 999 } 1000 else if (type == XMLSymbols.fNMTOKENSymbol || 1001 type == XMLSymbols.fENUMERATIONSymbol) { 1002 1003 if (!isValidNmtoken(value)) { 1004 ok = false; 1005 } 1006 } 1007 1008 if (type == XMLSymbols.fNOTATIONSymbol || 1009 type == XMLSymbols.fENUMERATIONSymbol) { 1010 ok = false; 1011 for (int i=0; i<enumeration.length; i++) { 1012 if (defaultValue.equals(enumeration[i])) { 1013 ok = true; 1014 } 1015 } 1016 } 1017 1018 } 1019 if (!ok) { 1020 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1021 "MSG_ATT_DEFAULT_INVALID", 1022 new Object[]{attributeName, value}, 1023 XMLErrorReporter.SEVERITY_ERROR); 1024 } 1025 } 1026 } 1027 1028 // call handlers 1029 if(fDTDGrammar != null) 1030 fDTDGrammar.attributeDecl(elementName, attributeName, 1031 type, enumeration, 1032 defaultType, defaultValue, nonNormalizedDefaultValue, augs); 1033 if (fDTDHandler != null) { 1034 fDTDHandler.attributeDecl(elementName, attributeName, 1035 type, enumeration, 1036 defaultType, defaultValue, nonNormalizedDefaultValue, augs); 1037 } 1038 1039 } // attributeDecl(String,String,String,String[],String,XMLString, XMLString, Augmentations) 1040 1041 /** 1042 * The end of an attribute list. 1043 * 1044 * @param augs Additional information that may include infoset 1045 * augmentations. 1046 * 1047 * @throws XNIException Thrown by handler to signal an error. 1048 */ 1049 public void endAttlist(Augmentations augs) throws XNIException { 1050 1051 // call handlers 1052 if(fDTDGrammar != null) 1053 fDTDGrammar.endAttlist(augs); 1054 if (fDTDHandler != null) { 1055 fDTDHandler.endAttlist(augs); 1056 } 1057 1058 } // endAttlist() 1059 1060 /** 1061 * An internal entity declaration. 1062 * 1063 * @param name The name of the entity. Parameter entity names start with 1064 * '%', whereas the name of a general entity is just the 1065 * entity name. 1066 * @param text The value of the entity. 1067 * @param nonNormalizedText The non-normalized value of the entity. This 1068 * value contains the same sequence of characters that was in 1069 * the internal entity declaration, without any entity 1070 * references expanded. 1071 * @param augs Additional information that may include infoset 1072 * augmentations. 1073 * 1074 * @throws XNIException Thrown by handler to signal an error. 1075 */ 1076 public void internalEntityDecl(String name, XMLString text, 1077 XMLString nonNormalizedText, 1078 Augmentations augs) throws XNIException { 1079 1080 DTDGrammar grammar = (fDTDGrammar != null? fDTDGrammar: fGrammarBucket.getActiveGrammar()); 1081 int index = grammar.getEntityDeclIndex(name) ; 1082 1083 //If the same entity is declared more than once, the first declaration 1084 //encountered is binding, SAX requires only effective(first) declaration 1085 //to be reported to the application 1086 1087 //REVISIT: Does it make sense to pass duplicate Entity information across 1088 //the pipeline -- nb? 1089 1090 //its a new entity and hasn't been declared. 1091 if(index == -1){ 1092 //store internal entity declaration in grammar 1093 if(fDTDGrammar != null) 1094 fDTDGrammar.internalEntityDecl(name, text, nonNormalizedText, augs); 1095 // call handlers 1096 if (fDTDHandler != null) { 1097 fDTDHandler.internalEntityDecl(name, text, nonNormalizedText, augs); 1098 } 1099 } 1100 1101 } // internalEntityDecl(String,XMLString,XMLString) 1102 1103 1104 /** 1105 * An external entity declaration. 1106 * 1107 * @param name The name of the entity. Parameter entity names start 1108 * with '%', whereas the name of a general entity is just 1109 * the entity name. 1110 * @param identifier An object containing all location information 1111 * pertinent to this external entity. 1112 * @param augs Additional information that may include infoset 1113 * augmentations. 1114 * 1115 * @throws XNIException Thrown by handler to signal an error. 1116 */ 1117 public void externalEntityDecl(String name, XMLResourceIdentifier identifier, 1118 Augmentations augs) throws XNIException { 1119 1120 DTDGrammar grammar = (fDTDGrammar != null? fDTDGrammar: fGrammarBucket.getActiveGrammar()); 1121 int index = grammar.getEntityDeclIndex(name) ; 1122 1123 //If the same entity is declared more than once, the first declaration 1124 //encountered is binding, SAX requires only effective(first) declaration 1125 //to be reported to the application 1126 1127 //REVISIT: Does it make sense to pass duplicate entity information across 1128 //the pipeline -- nb? 1129 1130 //its a new entity and hasn't been declared. 1131 if(index == -1){ 1132 //store external entity declaration in grammar 1133 if(fDTDGrammar != null) 1134 fDTDGrammar.externalEntityDecl(name, identifier, augs); 1135 // call handlers 1136 if (fDTDHandler != null) { 1137 fDTDHandler.externalEntityDecl(name, identifier, augs); 1138 } 1139 } 1140 1141 } // externalEntityDecl(String,XMLResourceIdentifier, Augmentations) 1142 1143 /** 1144 * An unparsed entity declaration. 1145 * 1146 * @param name The name of the entity. 1147 * @param identifier An object containing all location information 1148 * pertinent to this entity. 1149 * @param notation The name of the notation. 1150 * @param augs Additional information that may include infoset 1151 * augmentations. 1152 * 1153 * @throws XNIException Thrown by handler to signal an error. 1154 */ 1155 public void unparsedEntityDecl(String name, XMLResourceIdentifier identifier, 1156 String notation, 1157 Augmentations augs) throws XNIException { 1158 1159 // VC: Notation declared, in the production of NDataDecl 1160 if (fValidation) { 1161 fNDataDeclNotations.put(name, notation); 1162 } 1163 1164 // call handlers 1165 if(fDTDGrammar != null) 1166 fDTDGrammar.unparsedEntityDecl(name, identifier, notation, augs); 1167 if (fDTDHandler != null) { 1168 fDTDHandler.unparsedEntityDecl(name, identifier, notation, augs); 1169 } 1170 1171 } // unparsedEntityDecl(String,XMLResourceIdentifier,String,Augmentations) 1172 1173 /** 1174 * A notation declaration 1175 * 1176 * @param name The name of the notation. 1177 * @param identifier An object containing all location information 1178 * pertinent to this notation. 1179 * @param augs Additional information that may include infoset 1180 * augmentations. 1181 * 1182 * @throws XNIException Thrown by handler to signal an error. 1183 */ 1184 public void notationDecl(String name, XMLResourceIdentifier identifier, 1185 Augmentations augs) throws XNIException { 1186 1187 // VC: Unique Notation Name 1188 if (fValidation) { 1189 DTDGrammar grammar = (fDTDGrammar != null ? fDTDGrammar : fGrammarBucket.getActiveGrammar()); 1190 if (grammar.getNotationDeclIndex(name) != -1) { 1191 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1192 "UniqueNotationName", 1193 new Object[]{name}, 1194 XMLErrorReporter.SEVERITY_ERROR); 1195 } 1196 } 1197 1198 // call handlers 1199 if(fDTDGrammar != null) 1200 fDTDGrammar.notationDecl(name, identifier, augs); 1201 if (fDTDHandler != null) { 1202 fDTDHandler.notationDecl(name, identifier, augs); 1203 } 1204 1205 } // notationDecl(String,XMLResourceIdentifier, Augmentations) 1206 1207 /** 1208 * The start of a conditional section. 1209 * 1210 * @param type The type of the conditional section. This value will 1211 * either be CONDITIONAL_INCLUDE or CONDITIONAL_IGNORE. 1212 * @param augs Additional information that may include infoset 1213 * augmentations. 1214 * 1215 * @throws XNIException Thrown by handler to signal an error. 1216 * 1217 * @see #CONDITIONAL_INCLUDE 1218 * @see #CONDITIONAL_IGNORE 1219 */ 1220 public void startConditional(short type, Augmentations augs) throws XNIException { 1221 1222 // set state 1223 fInDTDIgnore = type == XMLDTDHandler.CONDITIONAL_IGNORE; 1224 1225 // call handlers 1226 if(fDTDGrammar != null) 1227 fDTDGrammar.startConditional(type, augs); 1228 if (fDTDHandler != null) { 1229 fDTDHandler.startConditional(type, augs); 1230 } 1231 1232 } // startConditional(short) 1233 1234 /** 1235 * The end of a conditional section. 1236 * 1237 * @param augs Additional information that may include infoset 1238 * augmentations. 1239 * 1240 * @throws XNIException Thrown by handler to signal an error. 1241 */ 1242 public void endConditional(Augmentations augs) throws XNIException { 1243 1244 // set state 1245 fInDTDIgnore = false; 1246 1247 // call handlers 1248 if(fDTDGrammar != null) 1249 fDTDGrammar.endConditional(augs); 1250 if (fDTDHandler != null) { 1251 fDTDHandler.endConditional(augs); 1252 } 1253 1254 } // endConditional() 1255 1256 /** 1257 * The end of the DTD. 1258 * 1259 * @param augs Additional information that may include infoset 1260 * augmentations. 1261 * 1262 * @throws XNIException Thrown by handler to signal an error. 1263 */ 1264 public void endDTD(Augmentations augs) throws XNIException { 1265 1266 1267 // save grammar 1268 if(fDTDGrammar != null) { 1269 fDTDGrammar.endDTD(augs); 1270 if(fGrammarPool != null) 1271 fGrammarPool.cacheGrammars(XMLGrammarDescription.XML_DTD, new Grammar[] {fDTDGrammar}); 1272 } 1273 if (fValidation) { 1274 DTDGrammar grammar = (fDTDGrammar != null? fDTDGrammar: fGrammarBucket.getActiveGrammar()); 1275 1276 // VC: Notation Declared. for external entity declaration [Production 76]. 1277 for (Map.Entry<String, String> entry : fNDataDeclNotations.entrySet()) { 1278 String notation = entry.getValue(); 1279 if (grammar.getNotationDeclIndex(notation) == -1) { 1280 String entity = entry.getKey(); 1281 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1282 "MSG_NOTATION_NOT_DECLARED_FOR_UNPARSED_ENTITYDECL", 1283 new Object[]{entity, notation}, 1284 XMLErrorReporter.SEVERITY_ERROR); 1285 } 1286 } 1287 1288 for (Map.Entry<String, String> entry : fNotationEnumVals.entrySet()) { 1289 String notation = entry.getKey(); 1290 if (grammar.getNotationDeclIndex(notation) == -1) { 1291 String attributeName = entry.getValue(); 1292 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1293 "MSG_NOTATION_NOT_DECLARED_FOR_NOTATIONTYPE_ATTRIBUTE", 1294 new Object[]{attributeName, notation}, 1295 XMLErrorReporter.SEVERITY_ERROR); 1296 } 1297 } 1298 1299 // VC: No Notation on Empty Element 1300 // An attribute of type NOTATION must not be declared on an element declared EMPTY. 1301 for (Map.Entry<String, String> entry : fTableOfNOTATIONAttributeNames.entrySet()) { 1302 String elementName = entry.getKey(); 1303 int elementIndex = grammar.getElementDeclIndex(elementName); 1304 if (grammar.getContentSpecType(elementIndex) == XMLElementDecl.TYPE_EMPTY) { 1305 String attributeName = entry.getValue(); 1306 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1307 "NoNotationOnEmptyElement", 1308 new Object[]{elementName, attributeName}, 1309 XMLErrorReporter.SEVERITY_ERROR); 1310 } 1311 } 1312 1313 // should be safe to release these references 1314 fTableOfIDAttributeNames = null; 1315 fTableOfNOTATIONAttributeNames = null; 1316 1317 // check whether each element referenced in a content model is declared 1318 if (fWarnOnUndeclaredElemdef) { 1319 checkDeclaredElements(grammar); 1320 } 1321 } 1322 1323 // call handlers 1324 if (fDTDHandler != null) { 1325 fDTDHandler.endDTD(augs); 1326 } 1327 1328 } // endDTD() 1329 1330 // sets the XMLDTDSource of this handler 1331 public void setDTDSource(XMLDTDSource source ) { 1332 fDTDSource = source; 1333 } // setDTDSource(XMLDTDSource) 1334 1335 // returns the XMLDTDSource of this handler 1336 public XMLDTDSource getDTDSource() { 1337 return fDTDSource; 1338 } // getDTDSource(): XMLDTDSource 1339 1340 // 1341 // XMLDTDContentModelHandler methods 1342 // 1343 1344 // sets the XMLContentModelDTDSource of this handler 1345 public void setDTDContentModelSource(XMLDTDContentModelSource source ) { 1346 fDTDContentModelSource = source; 1347 } // setDTDContentModelSource(XMLDTDContentModelSource) 1348 1349 // returns the XMLDTDSource of this handler 1350 public XMLDTDContentModelSource getDTDContentModelSource() { 1351 return fDTDContentModelSource; 1352 } // getDTDContentModelSource(): XMLDTDContentModelSource 1353 1354 1355 /** 1356 * The start of a content model. Depending on the type of the content 1357 * model, specific methods may be called between the call to the 1358 * startContentModel method and the call to the endContentModel method. 1359 * 1360 * @param elementName The name of the element. 1361 * @param augs Additional information that may include infoset 1362 * augmentations. 1363 * 1364 * @throws XNIException Thrown by handler to signal an error. 1365 */ 1366 public void startContentModel(String elementName, Augmentations augs) 1367 throws XNIException { 1368 1369 if (fValidation) { 1370 fDTDElementDeclName = elementName; 1371 fMixedElementTypes.clear(); 1372 } 1373 1374 // call handlers 1375 if(fDTDGrammar != null) 1376 fDTDGrammar.startContentModel(elementName, augs); 1377 if (fDTDContentModelHandler != null) { 1378 fDTDContentModelHandler.startContentModel(elementName, augs); 1379 } 1380 1381 } // startContentModel(String) 1382 1383 /** 1384 * A content model of ANY. 1385 * 1386 * @param augs Additional information that may include infoset 1387 * augmentations. 1388 * 1389 * @throws XNIException Thrown by handler to signal an error. 1390 * 1391 * @see #empty 1392 * @see #startGroup 1393 */ 1394 public void any(Augmentations augs) throws XNIException { 1395 if(fDTDGrammar != null) 1396 fDTDGrammar.any(augs); 1397 if (fDTDContentModelHandler != null) { 1398 fDTDContentModelHandler.any(augs); 1399 } 1400 } // any() 1401 1402 /** 1403 * A content model of EMPTY. 1404 * 1405 * @param augs Additional information that may include infoset 1406 * augmentations. 1407 * 1408 * @throws XNIException Thrown by handler to signal an error. 1409 * 1410 * @see #any 1411 * @see #startGroup 1412 */ 1413 public void empty(Augmentations augs) throws XNIException { 1414 if(fDTDGrammar != null) 1415 fDTDGrammar.empty(augs); 1416 if (fDTDContentModelHandler != null) { 1417 fDTDContentModelHandler.empty(augs); 1418 } 1419 } // empty() 1420 1421 /** 1422 * A start of either a mixed or children content model. A mixed 1423 * content model will immediately be followed by a call to the 1424 * <code>pcdata()</code> method. A children content model will 1425 * contain additional groups and/or elements. 1426 * 1427 * @param augs Additional information that may include infoset 1428 * augmentations. 1429 * 1430 * @throws XNIException Thrown by handler to signal an error. 1431 * 1432 * @see #any 1433 * @see #empty 1434 */ 1435 public void startGroup(Augmentations augs) throws XNIException { 1436 1437 fMixed = false; 1438 // call handlers 1439 if(fDTDGrammar != null) 1440 fDTDGrammar.startGroup(augs); 1441 if (fDTDContentModelHandler != null) { 1442 fDTDContentModelHandler.startGroup(augs); 1443 } 1444 1445 } // startGroup() 1446 1447 /** 1448 * The appearance of "#PCDATA" within a group signifying a 1449 * mixed content model. This method will be the first called 1450 * following the content model's <code>startGroup()</code>. 1451 * 1452 * @param augs Additional information that may include infoset 1453 * augmentations. 1454 * 1455 * @throws XNIException Thrown by handler to signal an error. 1456 * 1457 * @see #startGroup 1458 */ 1459 public void pcdata(Augmentations augs) { 1460 fMixed = true; 1461 if(fDTDGrammar != null) 1462 fDTDGrammar.pcdata(augs); 1463 if (fDTDContentModelHandler != null) { 1464 fDTDContentModelHandler.pcdata(augs); 1465 } 1466 } // pcdata() 1467 1468 /** 1469 * A referenced element in a mixed or children content model. 1470 * 1471 * @param elementName The name of the referenced element. 1472 * @param augs Additional information that may include infoset 1473 * augmentations. 1474 * 1475 * @throws XNIException Thrown by handler to signal an error. 1476 */ 1477 public void element(String elementName, Augmentations augs) throws XNIException { 1478 1479 // check VC: No duplicate Types, in a single mixed-content declaration 1480 if (fMixed && fValidation) { 1481 if (fMixedElementTypes.contains(elementName)) { 1482 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1483 "DuplicateTypeInMixedContent", 1484 new Object[]{fDTDElementDeclName, elementName}, 1485 XMLErrorReporter.SEVERITY_ERROR); 1486 } 1487 else { 1488 fMixedElementTypes.add(elementName); 1489 } 1490 } 1491 1492 // call handlers 1493 if(fDTDGrammar != null) 1494 fDTDGrammar.element(elementName, augs); 1495 if (fDTDContentModelHandler != null) { 1496 fDTDContentModelHandler.element(elementName, augs); 1497 } 1498 1499 } // childrenElement(String) 1500 1501 /** 1502 * The separator between choices or sequences of a mixed or children 1503 * content model. 1504 * 1505 * @param separator The type of children separator. 1506 * @param augs Additional information that may include infoset 1507 * augmentations. 1508 * 1509 * @throws XNIException Thrown by handler to signal an error. 1510 * 1511 * @see #SEPARATOR_CHOICE 1512 * @see #SEPARATOR_SEQUENCE 1513 */ 1514 public void separator(short separator, Augmentations augs) 1515 throws XNIException { 1516 1517 // call handlers 1518 if(fDTDGrammar != null) 1519 fDTDGrammar.separator(separator, augs); 1520 if (fDTDContentModelHandler != null) { 1521 fDTDContentModelHandler.separator(separator, augs); 1522 } 1523 1524 } // separator(short) 1525 1526 /** 1527 * The occurrence count for a child in a children content model or 1528 * for the mixed content model group. 1529 * 1530 * @param occurrence The occurrence count for the last element 1531 * or group. 1532 * @param augs Additional information that may include infoset 1533 * augmentations. 1534 * 1535 * @throws XNIException Thrown by handler to signal an error. 1536 * 1537 * @see #OCCURS_ZERO_OR_ONE 1538 * @see #OCCURS_ZERO_OR_MORE 1539 * @see #OCCURS_ONE_OR_MORE 1540 */ 1541 public void occurrence(short occurrence, Augmentations augs) 1542 throws XNIException { 1543 1544 // call handlers 1545 if(fDTDGrammar != null) 1546 fDTDGrammar.occurrence(occurrence, augs); 1547 if (fDTDContentModelHandler != null) { 1548 fDTDContentModelHandler.occurrence(occurrence, augs); 1549 } 1550 1551 } // occurrence(short) 1552 1553 /** 1554 * The end of a group for mixed or children content models. 1555 * 1556 * @param augs Additional information that may include infoset 1557 * augmentations. 1558 * 1559 * @throws XNIException Thrown by handler to signal an error. 1560 */ 1561 public void endGroup(Augmentations augs) throws XNIException { 1562 1563 // call handlers 1564 if(fDTDGrammar != null) 1565 fDTDGrammar.endGroup(augs); 1566 if (fDTDContentModelHandler != null) { 1567 fDTDContentModelHandler.endGroup(augs); 1568 } 1569 1570 } // endGroup() 1571 1572 /** 1573 * The end of a content model. 1574 * 1575 * @param augs Additional information that may include infoset 1576 * augmentations. 1577 * 1578 * @throws XNIException Thrown by handler to signal an error. 1579 */ 1580 public void endContentModel(Augmentations augs) throws XNIException { 1581 1582 // call handlers 1583 if(fDTDGrammar != null) 1584 fDTDGrammar.endContentModel(augs); 1585 if (fDTDContentModelHandler != null) { 1586 fDTDContentModelHandler.endContentModel(augs); 1587 } 1588 1589 } // endContentModel() 1590 1591 // 1592 // Private methods 1593 // 1594 1595 /** 1596 * Normalize the attribute value of a non CDATA default attribute 1597 * collapsing sequences of space characters (x20) 1598 * 1599 * @param value The value to normalize 1600 * @return Whether the value was changed or not. 1601 */ 1602 private boolean normalizeDefaultAttrValue(XMLString value) { 1603 1604 boolean skipSpace = true; // skip leading spaces 1605 int current = value.offset; 1606 int end = value.offset + value.length; 1607 for (int i = value.offset; i < end; i++) { 1608 if (value.ch[i] == ' ') { 1609 if (!skipSpace) { 1610 // take the first whitespace as a space and skip the others 1611 value.ch[current++] = ' '; 1612 skipSpace = true; 1613 } 1614 else { 1615 // just skip it. 1616 } 1617 } 1618 else { 1619 // simply shift non space chars if needed 1620 if (current != i) { 1621 value.ch[current] = value.ch[i]; 1622 } 1623 current++; 1624 skipSpace = false; 1625 } 1626 } 1627 if (current != end) { 1628 if (skipSpace) { 1629 // if we finished on a space trim it 1630 current--; 1631 } 1632 // set the new value length 1633 value.length = current - value.offset; 1634 return true; 1635 } 1636 return false; 1637 } 1638 1639 protected boolean isValidNmtoken(String nmtoken) { 1640 return XMLChar.isValidNmtoken(nmtoken); 1641 } // isValidNmtoken(String): boolean 1642 1643 protected boolean isValidName(String name) { 1644 return XMLChar.isValidName(name); 1645 } // isValidName(String): boolean 1646 1647 /** 1648 * Checks that all elements referenced in content models have 1649 * been declared. This method calls out to the error handler 1650 * to indicate warnings. 1651 */ 1652 private void checkDeclaredElements(DTDGrammar grammar) { 1653 int elementIndex = grammar.getFirstElementDeclIndex(); 1654 XMLContentSpec contentSpec = new XMLContentSpec(); 1655 while (elementIndex >= 0) { 1656 int type = grammar.getContentSpecType(elementIndex); 1657 if (type == XMLElementDecl.TYPE_CHILDREN || type == XMLElementDecl.TYPE_MIXED) { 1658 checkDeclaredElements(grammar, 1659 elementIndex, 1660 grammar.getContentSpecIndex(elementIndex), 1661 contentSpec); 1662 } 1663 elementIndex = grammar.getNextElementDeclIndex(elementIndex); 1664 } 1665 } 1666 1667 /** 1668 * Does a recursive (if necessary) check on the specified element's 1669 * content spec to make sure that all children refer to declared 1670 * elements. 1671 */ 1672 private void checkDeclaredElements(DTDGrammar grammar, int elementIndex, 1673 int contentSpecIndex, XMLContentSpec contentSpec) { 1674 grammar.getContentSpec(contentSpecIndex, contentSpec); 1675 if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_LEAF) { 1676 String value = (String) contentSpec.value; 1677 if (value != null && grammar.getElementDeclIndex(value) == -1) { 1678 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1679 "UndeclaredElementInContentSpec", 1680 new Object[]{grammar.getElementDeclName(elementIndex).rawname, value}, 1681 XMLErrorReporter.SEVERITY_WARNING); 1682 } 1683 } 1684 // It's not a leaf, so we have to recurse its left and maybe right 1685 // nodes. Save both values before we recurse and trash the node. 1686 else if ((contentSpec.type == XMLContentSpec.CONTENTSPECNODE_CHOICE) 1687 || (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_SEQ)) { 1688 final int leftNode = ((int[])contentSpec.value)[0]; 1689 final int rightNode = ((int[])contentSpec.otherValue)[0]; 1690 // Recurse on both children. 1691 checkDeclaredElements(grammar, elementIndex, leftNode, contentSpec); 1692 checkDeclaredElements(grammar, elementIndex, rightNode, contentSpec); 1693 } 1694 else if (contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_MORE 1695 || contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ZERO_OR_ONE 1696 || contentSpec.type == XMLContentSpec.CONTENTSPECNODE_ONE_OR_MORE) { 1697 final int leftNode = ((int[])contentSpec.value)[0]; 1698 checkDeclaredElements(grammar, elementIndex, leftNode, contentSpec); 1699 } 1700 } 1701 1702 } // class XMLDTDProcessor