1 /* 2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 3 */ 4 5 /* 6 * Copyright 2005 The Apache Software Foundation. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 */ 20 21 package com.sun.org.apache.xerces.internal.impl; 22 import com.sun.xml.internal.stream.dtd.nonvalidating.DTDGrammar; 23 import java.io.EOFException; 24 import java.io.IOException; 25 26 import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter; 27 28 import com.sun.org.apache.xerces.internal.util.SymbolTable; 29 import com.sun.org.apache.xerces.internal.util.XMLAttributesImpl; 30 import com.sun.org.apache.xerces.internal.util.XMLChar; 31 import com.sun.org.apache.xerces.internal.util.XMLStringBuffer; 32 33 import com.sun.org.apache.xerces.internal.xni.XMLDTDContentModelHandler; 34 import com.sun.org.apache.xerces.internal.xni.XMLDTDHandler; 35 import com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier; 36 import com.sun.org.apache.xerces.internal.xni.XMLString; 37 import com.sun.org.apache.xerces.internal.xni.XNIException; 38 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponent; 39 import com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager; 40 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; 41 import com.sun.org.apache.xerces.internal.xni.parser.XMLDTDScanner; 42 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource; 43 import com.sun.org.apache.xerces.internal.xni.Augmentations; 44 import com.sun.org.apache.xerces.internal.impl.XMLErrorReporter; 45 import com.sun.org.apache.xerces.internal.impl.XMLEntityHandler; 46 import com.sun.org.apache.xerces.internal.impl.Constants; 47 import com.sun.org.apache.xerces.internal.utils.XMLLimitAnalyzer; 48 import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager; 49 import com.sun.xml.internal.stream.Entity; 50 51 /** 52 * This class is responsible for scanning the declarations found 53 * in the internal and external subsets of a DTD in an XML document. 54 * The scanner acts as the sources for the DTD information which is 55 * communicated to the DTD handlers. 56 * <p> 57 * This component requires the following features and properties from the 58 * component manager that uses it: 59 * <ul> 60 * <li>http://xml.org/sax/features/validation</li> 61 * <li>http://apache.org/xml/features/scanner/notify-char-refs</li> 62 * <li>http://apache.org/xml/properties/internal/symbol-table</li> 63 * <li>http://apache.org/xml/properties/internal/error-reporter</li> 64 * <li>http://apache.org/xml/properties/internal/entity-manager</li> 65 * </ul> 66 * 67 * @author Arnaud Le Hors, IBM 68 * @author Andy Clark, IBM 69 * @author Glenn Marcy, IBM 70 * @author Eric Ye, IBM 71 * 72 * @version $Id: XMLDTDScannerImpl.java,v 1.8 2010-11-01 04:39:41 joehw Exp $ 73 */ 74 public class XMLDTDScannerImpl 75 extends XMLScanner 76 implements XMLDTDScanner, XMLComponent, XMLEntityHandler { 77 78 // 79 // Constants 80 // 81 82 // scanner states 83 84 /** Scanner state: end of input. */ 85 protected static final int SCANNER_STATE_END_OF_INPUT = 0; 86 87 /** Scanner state: text declaration. */ 88 protected static final int SCANNER_STATE_TEXT_DECL = 1; 89 90 /** Scanner state: markup declaration. */ 91 protected static final int SCANNER_STATE_MARKUP_DECL = 2; 92 93 // recognized features and properties 94 95 /** Recognized features. */ 96 private static final String[] RECOGNIZED_FEATURES = { 97 VALIDATION, 98 NOTIFY_CHAR_REFS, 99 }; 100 101 /** Feature defaults. */ 102 private static final Boolean[] FEATURE_DEFAULTS = { 103 null, 104 Boolean.FALSE, 105 }; 106 107 /** Recognized properties. */ 108 private static final String[] RECOGNIZED_PROPERTIES = { 109 SYMBOL_TABLE, 110 ERROR_REPORTER, 111 ENTITY_MANAGER, 112 }; 113 114 /** Property defaults. */ 115 private static final Object[] PROPERTY_DEFAULTS = { 116 null, 117 null, 118 null, 119 }; 120 121 // debugging 122 123 /** Debug scanner state. */ 124 private static final boolean DEBUG_SCANNER_STATE = false; 125 126 // 127 // Data 128 // 129 130 // handlers 131 132 /** DTD handler. */ 133 public XMLDTDHandler fDTDHandler = null; 134 135 /** DTD content model handler. */ 136 protected XMLDTDContentModelHandler fDTDContentModelHandler; 137 138 // state 139 140 /** Scanner state. */ 141 protected int fScannerState; 142 143 /** Standalone. */ 144 protected boolean fStandalone; 145 146 /** Seen external DTD. */ 147 protected boolean fSeenExternalDTD; 148 149 /** Seen external parameter entity. */ 150 protected boolean fSeenExternalPE; 151 152 // private data 153 154 /** Start DTD called. */ 155 private boolean fStartDTDCalled; 156 157 /** Default attribute */ 158 private XMLAttributesImpl fAttributes = new XMLAttributesImpl(); 159 160 /** 161 * Stack of content operators (either '|' or ',') in children 162 * content. 163 */ 164 private int[] fContentStack = new int[5]; 165 166 /** Size of content stack. */ 167 private int fContentDepth; 168 169 /** Parameter entity stack to check well-formedness. */ 170 private int[] fPEStack = new int[5]; 171 172 173 /** Parameter entity stack to report start/end entity calls. */ 174 private boolean[] fPEReport = new boolean[5]; 175 176 /** Number of opened parameter entities. */ 177 private int fPEDepth; 178 179 /** Markup depth. */ 180 private int fMarkUpDepth; 181 182 /** Number of opened external entities. */ 183 private int fExtEntityDepth; 184 185 /** Number of opened include sections. */ 186 private int fIncludeSectDepth; 187 188 // temporary variables 189 190 /** Array of 3 strings. */ 191 private String[] fStrings = new String[3]; 192 193 /** String. */ 194 private XMLString fString = new XMLString(); 195 196 /** String buffer. */ 197 private XMLStringBuffer fStringBuffer = new XMLStringBuffer(); 198 199 /** String buffer. */ 200 private XMLStringBuffer fStringBuffer2 = new XMLStringBuffer(); 201 202 /** Literal text. */ 203 private XMLString fLiteral = new XMLString(); 204 205 /** Literal text. */ 206 private XMLString fLiteral2 = new XMLString(); 207 208 /** Enumeration values. */ 209 private String[] fEnumeration = new String[5]; 210 211 /** Enumeration values count. */ 212 private int fEnumerationCount; 213 214 /** Ignore conditional section buffer. */ 215 private XMLStringBuffer fIgnoreConditionalBuffer = new XMLStringBuffer(128); 216 217 /** Object contains grammar information for a non-validaing parser. */ 218 DTDGrammar nvGrammarInfo = null; 219 220 boolean nonValidatingMode = false; 221 // 222 // Constructors 223 // 224 225 /** Default constructor. */ 226 public XMLDTDScannerImpl() { 227 } // <init>() 228 229 /** Constructor for he use of non-XMLComponentManagers. */ 230 public XMLDTDScannerImpl(SymbolTable symbolTable, 231 XMLErrorReporter errorReporter, XMLEntityManager entityManager) { 232 fSymbolTable = symbolTable; 233 fErrorReporter = errorReporter; 234 fEntityManager = entityManager; 235 entityManager.setProperty(SYMBOL_TABLE, fSymbolTable); 236 } 237 238 // 239 // XMLDTDScanner methods 240 // 241 242 /** 243 * Sets the input source. 244 * 245 * @param inputSource The input source or null. 246 * 247 * @throws IOException Thrown on i/o error. 248 */ 249 public void setInputSource(XMLInputSource inputSource) throws IOException { 250 if (inputSource == null) { 251 // no system id was available 252 if (fDTDHandler != null) { 253 fDTDHandler.startDTD(null, null); 254 fDTDHandler.endDTD(null); 255 } 256 if (nonValidatingMode){ 257 nvGrammarInfo.startDTD(null,null); 258 nvGrammarInfo.endDTD(null); 259 } 260 return; 261 } 262 fEntityManager.setEntityHandler(this); 263 fEntityManager.startDTDEntity(inputSource); 264 } // setInputSource(XMLInputSource) 265 266 267 public void setLimitAnalyzer(XMLLimitAnalyzer limitAnalyzer) { 268 fLimitAnalyzer = limitAnalyzer; 269 } 270 271 /** 272 * Scans the external subset of the document. 273 * 274 * @param complete True if the scanner should scan the document 275 * completely, pushing all events to the registered 276 * document handler. A value of false indicates that 277 * that the scanner should only scan the next portion 278 * of the document and return. A scanner instance is 279 * permitted to completely scan a document if it does 280 * not support this "pull" scanning model. 281 * 282 * @return True if there is more to scan, false otherwise. 283 */ 284 public boolean scanDTDExternalSubset(boolean complete) 285 throws IOException, XNIException { 286 287 fEntityManager.setEntityHandler(this); 288 if (fScannerState == SCANNER_STATE_TEXT_DECL) { 289 fSeenExternalDTD = true; 290 boolean textDecl = scanTextDecl(); 291 if (fScannerState == SCANNER_STATE_END_OF_INPUT) { 292 return false; 293 } 294 else { 295 // next state is markup decls regardless of whether there 296 // is a TextDecl or not 297 setScannerState(SCANNER_STATE_MARKUP_DECL); 298 if (textDecl && !complete) { 299 return true; 300 } 301 } 302 } 303 // keep dispatching "events" 304 do { 305 if (!scanDecls(complete)) { 306 return false; 307 } 308 } while (complete); 309 310 // return that there is more to scan 311 return true; 312 313 } // scanDTDExternalSubset(boolean):boolean 314 315 /** 316 * Scans the internal subset of the document. 317 * 318 * @param complete True if the scanner should scan the document 319 * completely, pushing all events to the registered 320 * document handler. A value of false indicates that 321 * that the scanner should only scan the next portion 322 * of the document and return. A scanner instance is 323 * permitted to completely scan a document if it does 324 * not support this "pull" scanning model. 325 * @param standalone True if the document was specified as standalone. 326 * This value is important for verifying certain 327 * well-formedness constraints. 328 * @param hasExternalDTD True if the document has an external DTD. 329 * This allows the scanner to properly notify 330 * the handler of the end of the DTD in the 331 * absence of an external subset. 332 * 333 * @return True if there is more to scan, false otherwise. 334 */ 335 public boolean scanDTDInternalSubset(boolean complete, boolean standalone, 336 boolean hasExternalSubset) 337 throws IOException, XNIException { 338 // reset entity scanner 339 //xxx:stax getText() is supposed to return only DTD internal subset 340 //shouldn't we record position here before we go ahead ?? 341 342 fEntityScanner = (XMLEntityScanner)fEntityManager.getEntityScanner(); 343 fEntityManager.setEntityHandler(this); 344 fStandalone = standalone; 345 //System.out.println("state"+fScannerState); 346 if (fScannerState == SCANNER_STATE_TEXT_DECL) { 347 // call handler 348 if (fDTDHandler != null) { 349 fDTDHandler.startDTD(fEntityScanner, null); 350 fStartDTDCalled = true; 351 } 352 353 if (nonValidatingMode){ 354 fStartDTDCalled = true; 355 nvGrammarInfo.startDTD(fEntityScanner,null); 356 } 357 // set starting state for internal subset 358 setScannerState(SCANNER_STATE_MARKUP_DECL); 359 } 360 // keep dispatching "events" 361 do { 362 if (!scanDecls(complete)) { 363 // call handler 364 if (fDTDHandler != null && hasExternalSubset == false) { 365 fDTDHandler.endDTD(null); 366 } 367 if (nonValidatingMode && hasExternalSubset == false ){ 368 nvGrammarInfo.endDTD(null); 369 } 370 // we're done, set starting state for external subset 371 setScannerState(SCANNER_STATE_TEXT_DECL); 372 return false; 373 } 374 } while (complete); 375 376 // return that there is more to scan 377 return true; 378 379 } // scanDTDInternalSubset(boolean,boolean,boolean):boolean 380 381 // 382 // XMLComponent methods 383 // 384 385 /** 386 * reset 387 * 388 * @param componentManager 389 */ 390 public void reset(XMLComponentManager componentManager) 391 throws XMLConfigurationException { 392 393 super.reset(componentManager); 394 init(); 395 396 } // reset(XMLComponentManager) 397 398 // this is made for something like XMLDTDLoader--XMLComponentManager-free operation... 399 public void reset() { 400 super.reset(); 401 init(); 402 403 } 404 405 public void reset(PropertyManager props) { 406 setPropertyManager(props); 407 super.reset(props); 408 init() ; 409 nonValidatingMode = true; 410 //Revisit : Create new grammar until we implement GrammarPool. 411 nvGrammarInfo = new DTDGrammar(fSymbolTable); 412 } 413 /** 414 * Returns a list of feature identifiers that are recognized by 415 * this component. This method may return null if no features 416 * are recognized by this component. 417 */ 418 public String[] getRecognizedFeatures() { 419 return (String[])(RECOGNIZED_FEATURES.clone()); 420 } // getRecognizedFeatures():String[] 421 422 /** 423 * Returns a list of property identifiers that are recognized by 424 * this component. This method may return null if no properties 425 * are recognized by this component. 426 */ 427 public String[] getRecognizedProperties() { 428 return (String[])(RECOGNIZED_PROPERTIES.clone()); 429 } // getRecognizedProperties():String[] 430 431 /** 432 * Returns the default state for a feature, or null if this 433 * component does not want to report a default value for this 434 * feature. 435 * 436 * @param featureId The feature identifier. 437 * 438 * @since Xerces 2.2.0 439 */ 440 public Boolean getFeatureDefault(String featureId) { 441 for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { 442 if (RECOGNIZED_FEATURES[i].equals(featureId)) { 443 return FEATURE_DEFAULTS[i]; 444 } 445 } 446 return null; 447 } // getFeatureDefault(String):Boolean 448 449 /** 450 * Returns the default state for a property, or null if this 451 * component does not want to report a default value for this 452 * property. 453 * 454 * @param propertyId The property identifier. 455 * 456 * @since Xerces 2.2.0 457 */ 458 public Object getPropertyDefault(String propertyId) { 459 for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { 460 if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { 461 return PROPERTY_DEFAULTS[i]; 462 } 463 } 464 return null; 465 } // getPropertyDefault(String):Object 466 467 // 468 // XMLDTDSource methods 469 // 470 471 /** 472 * setDTDHandler 473 * 474 * @param dtdHandler 475 */ 476 public void setDTDHandler(XMLDTDHandler dtdHandler) { 477 fDTDHandler = dtdHandler; 478 } // setDTDHandler(XMLDTDHandler) 479 480 /** 481 * getDTDHandler 482 * 483 * @return the XMLDTDHandler 484 */ 485 public XMLDTDHandler getDTDHandler() { 486 return fDTDHandler; 487 } // getDTDHandler(): XMLDTDHandler 488 489 // 490 // XMLDTDContentModelSource methods 491 // 492 493 /** 494 * setDTDContentModelHandler 495 * 496 * @param dtdContentModelHandler 497 */ 498 public void setDTDContentModelHandler(XMLDTDContentModelHandler 499 dtdContentModelHandler) { 500 fDTDContentModelHandler = dtdContentModelHandler; 501 } // setDTDContentModelHandler 502 503 /** 504 * getDTDContentModelHandler 505 * 506 * @return XMLDTDContentModelHandler 507 */ 508 public XMLDTDContentModelHandler getDTDContentModelHandler() { 509 return fDTDContentModelHandler ; 510 } // setDTDContentModelHandler 511 512 // 513 // XMLEntityHandler methods 514 // 515 516 /** 517 * This method notifies of the start of an entity. The DTD has the 518 * pseudo-name of "[dtd]" parameter entity names start with '%'; and 519 * general entities are just specified by their name. 520 * 521 * @param name The name of the entity. 522 * @param identifier The resource identifier. 523 * @param encoding The auto-detected IANA encoding name of the entity 524 * stream. This value will be null in those situations 525 * where the entity encoding is not auto-detected (e.g. 526 * internal entities or a document entity that is 527 * parsed from a java.io.Reader). 528 * @param augs Additional information that may include infoset augmentations 529 * 530 * @throws XNIException Thrown by handler to signal an error. 531 */ 532 public void startEntity(String name, 533 XMLResourceIdentifier identifier, 534 String encoding, Augmentations augs) throws XNIException { 535 536 super.startEntity(name, identifier, encoding, augs); 537 538 boolean dtdEntity = name.equals("[dtd]"); 539 if (dtdEntity) { 540 // call handler 541 if (fDTDHandler != null && !fStartDTDCalled ) { 542 fDTDHandler.startDTD(fEntityScanner, null); 543 } 544 if (fDTDHandler != null) { 545 fDTDHandler.startExternalSubset(identifier,null); 546 } 547 fEntityManager.startExternalSubset(); 548 fEntityStore.startExternalSubset(); 549 fExtEntityDepth++; 550 } 551 else if (name.charAt(0) == '%') { 552 pushPEStack(fMarkUpDepth, fReportEntity); 553 if (fEntityScanner.isExternal()) { 554 fExtEntityDepth++; 555 } 556 } 557 558 // call handler 559 if (fDTDHandler != null && !dtdEntity && fReportEntity) { 560 fDTDHandler.startParameterEntity(name, identifier, encoding, null); 561 } 562 563 } // startEntity(String,XMLResourceIdentifier,String) 564 565 /** 566 * This method notifies the end of an entity. The DTD has the pseudo-name 567 * of "[dtd]" parameter entity names start with '%'; and general entities 568 * are just specified by their name. 569 * 570 * @param name The name of the entity. 571 * 572 * @throws XNIException Thrown by handler to signal an error. 573 */ 574 public void endEntity(String name, Augmentations augs) 575 throws XNIException, IOException { 576 577 super.endEntity(name, augs); 578 579 // if there is no data after the doctype 580 // 581 if (fScannerState == SCANNER_STATE_END_OF_INPUT) 582 return; 583 584 // Handle end of PE 585 boolean reportEntity = fReportEntity; 586 if (name.startsWith("%")) { 587 reportEntity = peekReportEntity(); 588 // check well-formedness of the entity 589 int startMarkUpDepth = popPEStack(); 590 // throw fatalError if this entity was incomplete and 591 // was a freestanding decl 592 if(startMarkUpDepth == 0 && 593 startMarkUpDepth < fMarkUpDepth) { 594 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 595 "ILL_FORMED_PARAMETER_ENTITY_WHEN_USED_IN_DECL", 596 new Object[]{ fEntityManager.fCurrentEntity.name}, 597 XMLErrorReporter.SEVERITY_FATAL_ERROR); 598 } 599 if (startMarkUpDepth != fMarkUpDepth) { 600 reportEntity = false; 601 if (fValidation) { 602 // Proper nesting of parameter entities is a Validity Constraint 603 // and must not be enforced when validation is off 604 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 605 "ImproperDeclarationNesting", 606 new Object[]{ name }, 607 XMLErrorReporter.SEVERITY_ERROR); 608 } 609 } 610 if (fEntityScanner.isExternal()) { 611 fExtEntityDepth--; 612 } 613 } 614 615 // call handler 616 boolean dtdEntity = name.equals("[dtd]"); 617 if (fDTDHandler != null && !dtdEntity && reportEntity) { 618 fDTDHandler.endParameterEntity(name, null); 619 } 620 621 // end DTD 622 if (dtdEntity) { 623 if (fIncludeSectDepth != 0) { 624 reportFatalError("IncludeSectUnterminated", null); 625 } 626 fScannerState = SCANNER_STATE_END_OF_INPUT; 627 // call handler 628 fEntityManager.endExternalSubset(); 629 fEntityStore.endExternalSubset(); 630 631 if (fDTDHandler != null) { 632 fDTDHandler.endExternalSubset(null); 633 fDTDHandler.endDTD(null); 634 } 635 fExtEntityDepth--; 636 } 637 638 //XML (Document Entity) is the last opened entity, however 639 //if for some reason DTD Scanner receives this callback 640 //there is something wrong (probably invalid XML), throw exception. 641 //or 642 //For standalone DTD loader, it might be the last opened entity 643 //and if this is the last opened entity and fMarkUpDepth != 0 or 644 //fIncludeSectDepth != 0 or fExtEntityDepth != 0 throw Exception 645 if (augs != null && Boolean.TRUE.equals(augs.getItem(Constants.LAST_ENTITY)) 646 && ( fMarkUpDepth != 0 || fExtEntityDepth !=0 || fIncludeSectDepth != 0)){ 647 throw new EOFException(); 648 } 649 650 } // endEntity(String) 651 652 // helper methods 653 654 /** 655 * Sets the scanner state. 656 * 657 * @param state The new scanner state. 658 */ 659 protected final void setScannerState(int state) { 660 661 fScannerState = state; 662 if (DEBUG_SCANNER_STATE) { 663 System.out.print("### setScannerState: "); 664 System.out.print(getScannerStateName(state)); 665 //System.out.println(); 666 } 667 668 } // setScannerState(int) 669 670 // 671 // Private methods 672 // 673 674 /** Returns the scanner state name. */ 675 private static String getScannerStateName(int state) { 676 677 if (DEBUG_SCANNER_STATE) { 678 switch (state) { 679 case SCANNER_STATE_END_OF_INPUT: return "SCANNER_STATE_END_OF_INPUT"; 680 case SCANNER_STATE_TEXT_DECL: return "SCANNER_STATE_TEXT_DECL"; 681 case SCANNER_STATE_MARKUP_DECL: return "SCANNER_STATE_MARKUP_DECL"; 682 } 683 } 684 685 return "??? ("+state+')'; 686 687 } // getScannerStateName(int):String 688 689 protected final boolean scanningInternalSubset() { 690 return fExtEntityDepth == 0; 691 } 692 693 /** 694 * start a parameter entity dealing with the textdecl if there is any 695 * 696 * @param name The name of the parameter entity to start (without the '%') 697 * @param literal Whether this is happening within a literal 698 */ 699 protected void startPE(String name, boolean literal) 700 throws IOException, XNIException { 701 int depth = fPEDepth; 702 String pName = "%"+name; 703 if (fValidation && !fEntityStore.isDeclaredEntity(pName)) { 704 fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,"EntityNotDeclared", 705 new Object[]{name}, XMLErrorReporter.SEVERITY_ERROR); 706 } 707 fEntityManager.startEntity(fSymbolTable.addSymbol(pName), 708 literal); 709 // if we actually got a new entity and it's external 710 // parse text decl if there is any 711 if (depth != fPEDepth && fEntityScanner.isExternal()) { 712 scanTextDecl(); 713 } 714 } 715 716 /** 717 * Dispatch an XML "event". 718 * 719 * @param complete True if this method is intended to scan 720 * and dispatch as much as possible. 721 * 722 * @return True if a TextDecl was scanned. 723 * 724 * @throws IOException Thrown on i/o error. 725 * @throws XNIException Thrown on parse error. 726 * 727 */ 728 protected final boolean scanTextDecl() 729 throws IOException, XNIException { 730 731 // scan XMLDecl 732 boolean textDecl = false; 733 if (fEntityScanner.skipString("<?xml")) { 734 fMarkUpDepth++; 735 // NOTE: special case where document starts with a PI 736 // whose name starts with "xml" (e.g. "xmlfoo") 737 if (isValidNameChar(fEntityScanner.peekChar())) { 738 fStringBuffer.clear(); 739 fStringBuffer.append("xml"); 740 while (isValidNameChar(fEntityScanner.peekChar())) { 741 fStringBuffer.append((char)fEntityScanner.scanChar()); 742 } 743 String target = 744 fSymbolTable.addSymbol(fStringBuffer.ch, 745 fStringBuffer.offset, 746 fStringBuffer.length); 747 scanPIData(target, fString); 748 } 749 750 // standard Text declaration 751 else { 752 // pseudo-attribute values 753 String version = null; 754 String encoding = null; 755 756 scanXMLDeclOrTextDecl(true, fStrings); 757 textDecl = true; 758 fMarkUpDepth--; 759 760 version = fStrings[0]; 761 encoding = fStrings[1]; 762 763 fEntityScanner.setEncoding(encoding); 764 765 // call handler 766 if (fDTDHandler != null) { 767 fDTDHandler.textDecl(version, encoding, null); 768 } 769 } 770 } 771 fEntityManager.fCurrentEntity.mayReadChunks = true; 772 773 return textDecl; 774 775 } // scanTextDecl(boolean):boolean 776 777 /** 778 * Scans a processing data. This is needed to handle the situation 779 * where a document starts with a processing instruction whose 780 * target name <em>starts with</em> "xml". (e.g. xmlfoo) 781 * 782 * @param target The PI target 783 * @param data The string to fill in with the data 784 */ 785 protected final void scanPIData(String target, XMLString data) 786 throws IOException, XNIException { 787 //Venu REVISIT 788 // super.scanPIData(target, data); 789 fMarkUpDepth--; 790 791 // call handler 792 if (fDTDHandler != null) { 793 fDTDHandler.processingInstruction(target, data, null); 794 } 795 796 } // scanPIData(String) 797 798 /** 799 * Scans a comment. 800 * <p> 801 * <pre> 802 * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' 803 * </pre> 804 * <p> 805 * <strong>Note:</strong> Called after scanning past '<!--' 806 */ 807 protected final void scanComment() throws IOException, XNIException { 808 809 fReportEntity = false; 810 scanComment(fStringBuffer); 811 fMarkUpDepth--; 812 813 // call handler 814 if (fDTDHandler != null) { 815 fDTDHandler.comment(fStringBuffer, null); 816 } 817 fReportEntity = true; 818 819 } // scanComment() 820 821 /** 822 * Scans an element declaration 823 * <p> 824 * <pre> 825 * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>' 826 * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children 827 * </pre> 828 * <p> 829 * <strong>Note:</strong> Called after scanning past '<!ELEMENT' 830 */ 831 protected final void scanElementDecl() throws IOException, XNIException { 832 833 // spaces 834 fReportEntity = false; 835 if (!skipSeparator(true, !scanningInternalSubset())) { 836 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL", 837 null); 838 } 839 840 // element name 841 String name = fEntityScanner.scanName(); 842 if (name == null) { 843 reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL", 844 null); 845 } 846 847 // spaces 848 if (!skipSeparator(true, !scanningInternalSubset())) { 849 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_CONTENTSPEC_IN_ELEMENTDECL", 850 new Object[]{name}); 851 } 852 853 // content model 854 if (fDTDContentModelHandler != null) { 855 fDTDContentModelHandler.startContentModel(name, null); 856 } 857 String contentModel = null; 858 fReportEntity = true; 859 if (fEntityScanner.skipString("EMPTY")) { 860 contentModel = "EMPTY"; 861 // call handler 862 if (fDTDContentModelHandler != null) { 863 fDTDContentModelHandler.empty(null); 864 } 865 } 866 else if (fEntityScanner.skipString("ANY")) { 867 contentModel = "ANY"; 868 // call handler 869 if (fDTDContentModelHandler != null) { 870 fDTDContentModelHandler.any(null); 871 } 872 } 873 else { 874 if (!fEntityScanner.skipChar('(')) { 875 reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN", 876 new Object[]{name}); 877 } 878 if (fDTDContentModelHandler != null) { 879 fDTDContentModelHandler.startGroup(null); 880 } 881 fStringBuffer.clear(); 882 fStringBuffer.append('('); 883 fMarkUpDepth++; 884 skipSeparator(false, !scanningInternalSubset()); 885 886 // Mixed content model 887 if (fEntityScanner.skipString("#PCDATA")) { 888 scanMixed(name); 889 } 890 else { // children content 891 scanChildren(name); 892 } 893 contentModel = fStringBuffer.toString(); 894 } 895 896 // call handler 897 if (fDTDContentModelHandler != null) { 898 fDTDContentModelHandler.endContentModel(null); 899 } 900 901 fReportEntity = false; 902 skipSeparator(false, !scanningInternalSubset()); 903 // end 904 if (!fEntityScanner.skipChar('>')) { 905 reportFatalError("ElementDeclUnterminated", new Object[]{name}); 906 } 907 fReportEntity = true; 908 fMarkUpDepth--; 909 910 // call handler 911 if (fDTDHandler != null) { 912 fDTDHandler.elementDecl(name, contentModel, null); 913 } 914 if (nonValidatingMode) nvGrammarInfo.elementDecl(name, contentModel, null); 915 } // scanElementDecl() 916 917 /** 918 * scan Mixed content model 919 * This assumes the content model has been parsed up to #PCDATA and 920 * can simply append to fStringBuffer. 921 * <pre> 922 * [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' 923 * | '(' S? '#PCDATA' S? ')' 924 * </pre> 925 * 926 * @param elName The element type name this declaration is about. 927 * 928 * <strong>Note:</strong> Called after scanning past '(#PCDATA'. 929 */ 930 private final void scanMixed(String elName) 931 throws IOException, XNIException { 932 933 String childName = null; 934 935 fStringBuffer.append("#PCDATA"); 936 // call handler 937 if (fDTDContentModelHandler != null) { 938 fDTDContentModelHandler.pcdata(null); 939 } 940 skipSeparator(false, !scanningInternalSubset()); 941 while (fEntityScanner.skipChar('|')) { 942 fStringBuffer.append('|'); 943 // call handler 944 if (fDTDContentModelHandler != null) { 945 fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_CHOICE, 946 null); 947 } 948 skipSeparator(false, !scanningInternalSubset()); 949 950 childName = fEntityScanner.scanName(); 951 if (childName == null) { 952 reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_MIXED_CONTENT", 953 new Object[]{elName}); 954 } 955 fStringBuffer.append(childName); 956 // call handler 957 if (fDTDContentModelHandler != null) { 958 fDTDContentModelHandler.element(childName, null); 959 } 960 skipSeparator(false, !scanningInternalSubset()); 961 } 962 // The following check must be done in a single call (as opposed to one 963 // for ')' and then one for '*') to guarantee that callbacks are 964 // properly nested. We do not want to trigger endEntity too early in 965 // case we cross the boundary of an entity between the two characters. 966 if (fEntityScanner.skipString(")*")) { 967 fStringBuffer.append(")*"); 968 // call handler 969 if (fDTDContentModelHandler != null) { 970 fDTDContentModelHandler.endGroup(null); 971 fDTDContentModelHandler.occurrence(XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE, 972 null); 973 } 974 } 975 else if (childName != null) { 976 reportFatalError("MixedContentUnterminated", 977 new Object[]{elName}); 978 } 979 else if (fEntityScanner.skipChar(')')){ 980 fStringBuffer.append(')'); 981 // call handler 982 if (fDTDContentModelHandler != null) { 983 fDTDContentModelHandler.endGroup(null); 984 } 985 } 986 else { 987 reportFatalError("MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN", 988 new Object[]{elName}); 989 } 990 fMarkUpDepth--; 991 // we are done 992 } 993 994 /** 995 * scan children content model 996 * This assumes it can simply append to fStringBuffer. 997 * <pre> 998 * [47] children ::= (choice | seq) ('?' | '*' | '+')? 999 * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')? 1000 * [49] choice ::= '(' S? cp ( S? '|' S? cp )+ S? ')' 1001 * [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')' 1002 * </pre> 1003 * 1004 * @param elName The element type name this declaration is about. 1005 * 1006 * <strong>Note:</strong> Called after scanning past the first open 1007 * paranthesis. 1008 */ 1009 private final void scanChildren(String elName) 1010 throws IOException, XNIException { 1011 1012 fContentDepth = 0; 1013 pushContentStack(0); 1014 int currentOp = 0; 1015 int c; 1016 while (true) { 1017 if (fEntityScanner.skipChar('(')) { 1018 fMarkUpDepth++; 1019 fStringBuffer.append('('); 1020 // call handler 1021 if (fDTDContentModelHandler != null) { 1022 fDTDContentModelHandler.startGroup(null); 1023 } 1024 // push current op on stack and reset it 1025 pushContentStack(currentOp); 1026 currentOp = 0; 1027 skipSeparator(false, !scanningInternalSubset()); 1028 continue; 1029 } 1030 skipSeparator(false, !scanningInternalSubset()); 1031 String childName = fEntityScanner.scanName(); 1032 if (childName == null) { 1033 reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN", 1034 new Object[]{elName}); 1035 return; 1036 } 1037 // call handler 1038 if (fDTDContentModelHandler != null) { 1039 fDTDContentModelHandler.element(childName, null); 1040 } 1041 fStringBuffer.append(childName); 1042 c = fEntityScanner.peekChar(); 1043 if (c == '?' || c == '*' || c == '+') { 1044 // call handler 1045 if (fDTDContentModelHandler != null) { 1046 short oc; 1047 if (c == '?') { 1048 oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE; 1049 } 1050 else if (c == '*') { 1051 oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE; 1052 } 1053 else { 1054 oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE; 1055 } 1056 fDTDContentModelHandler.occurrence(oc, null); 1057 } 1058 fEntityScanner.scanChar(); 1059 fStringBuffer.append((char)c); 1060 } 1061 while (true) { 1062 skipSeparator(false, !scanningInternalSubset()); 1063 c = fEntityScanner.peekChar(); 1064 if (c == ',' && currentOp != '|') { 1065 currentOp = c; 1066 // call handler 1067 if (fDTDContentModelHandler != null) { 1068 fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_SEQUENCE, 1069 null); 1070 } 1071 fEntityScanner.scanChar(); 1072 fStringBuffer.append(','); 1073 break; 1074 } 1075 else if (c == '|' && currentOp != ',') { 1076 currentOp = c; 1077 // call handler 1078 if (fDTDContentModelHandler != null) { 1079 fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_CHOICE, 1080 null); 1081 } 1082 fEntityScanner.scanChar(); 1083 fStringBuffer.append('|'); 1084 break; 1085 } 1086 else if (c != ')') { 1087 reportFatalError("MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN", 1088 new Object[]{elName}); 1089 } 1090 // call handler 1091 if (fDTDContentModelHandler != null) { 1092 fDTDContentModelHandler.endGroup(null); 1093 } 1094 // restore previous op 1095 currentOp = popContentStack(); 1096 short oc; 1097 // The following checks must be done in a single call (as 1098 // opposed to one for ')' and then one for '?', '*', and '+') 1099 // to guarantee that callbacks are properly nested. We do not 1100 // want to trigger endEntity too early in case we cross the 1101 // boundary of an entity between the two characters. 1102 if (fEntityScanner.skipString(")?")) { 1103 fStringBuffer.append(")?"); 1104 // call handler 1105 if (fDTDContentModelHandler != null) { 1106 oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE; 1107 fDTDContentModelHandler.occurrence(oc, null); 1108 } 1109 } 1110 else if (fEntityScanner.skipString(")+")) { 1111 fStringBuffer.append(")+"); 1112 // call handler 1113 if (fDTDContentModelHandler != null) { 1114 oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE; 1115 fDTDContentModelHandler.occurrence(oc, null); 1116 } 1117 } 1118 else if (fEntityScanner.skipString(")*")) { 1119 fStringBuffer.append(")*"); 1120 // call handler 1121 if (fDTDContentModelHandler != null) { 1122 oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE; 1123 fDTDContentModelHandler.occurrence(oc, null); 1124 } 1125 } 1126 else { 1127 // no occurrence specified 1128 fEntityScanner.scanChar(); 1129 fStringBuffer.append(')'); 1130 } 1131 fMarkUpDepth--; 1132 if (fContentDepth == 0) { 1133 return; 1134 } 1135 } 1136 skipSeparator(false, !scanningInternalSubset()); 1137 } 1138 } 1139 1140 /** 1141 * Scans an attlist declaration 1142 * <p> 1143 * <pre> 1144 * [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>' 1145 * [53] AttDef ::= S Name S AttType S DefaultDecl 1146 * </pre> 1147 * <p> 1148 * <strong>Note:</strong> Called after scanning past '<!ATTLIST' 1149 */ 1150 protected final void scanAttlistDecl() throws IOException, XNIException { 1151 1152 // spaces 1153 fReportEntity = false; 1154 if (!skipSeparator(true, !scanningInternalSubset())) { 1155 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ATTLISTDECL", 1156 null); 1157 } 1158 1159 // element name 1160 String elName = fEntityScanner.scanName(); 1161 if (elName == null) { 1162 reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ATTLISTDECL", 1163 null); 1164 } 1165 1166 // call handler 1167 if (fDTDHandler != null) { 1168 fDTDHandler.startAttlist(elName, null); 1169 } 1170 1171 // spaces 1172 if (!skipSeparator(true, !scanningInternalSubset())) { 1173 // no space, is it the end yet? 1174 if (fEntityScanner.skipChar('>')) { 1175 // yes, stop here 1176 // call handler 1177 if (fDTDHandler != null) { 1178 fDTDHandler.endAttlist(null); 1179 } 1180 fMarkUpDepth--; 1181 return; 1182 } 1183 else { 1184 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ATTRIBUTE_NAME_IN_ATTDEF", 1185 new Object[]{elName}); 1186 } 1187 } 1188 1189 // definitions 1190 while (!fEntityScanner.skipChar('>')) { 1191 String name = fEntityScanner.scanName(); 1192 if (name == null) { 1193 reportFatalError("AttNameRequiredInAttDef", 1194 new Object[]{elName}); 1195 } 1196 // spaces 1197 if (!skipSeparator(true, !scanningInternalSubset())) { 1198 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ATTTYPE_IN_ATTDEF", 1199 new Object[]{elName, name}); 1200 } 1201 // type 1202 String type = scanAttType(elName, name); 1203 1204 // spaces 1205 if (!skipSeparator(true, !scanningInternalSubset())) { 1206 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_DEFAULTDECL_IN_ATTDEF", 1207 new Object[]{elName, name}); 1208 } 1209 1210 // default decl 1211 String defaultType = scanAttDefaultDecl(elName, name, 1212 type, 1213 fLiteral, fLiteral2); 1214 // REVISIT: Should we do anything with the non-normalized 1215 // default attribute value? -Ac 1216 // yes--according to bug 5073. - neilg 1217 String[] enumr = null; 1218 if( fDTDHandler != null || nonValidatingMode){ 1219 if (fEnumerationCount != 0) { 1220 enumr = new String[fEnumerationCount]; 1221 System.arraycopy(fEnumeration, 0, enumr, 1222 0, fEnumerationCount); 1223 } 1224 } 1225 // call handler 1226 // Determine whether the default value to be passed should be null. 1227 // REVISIT: should probably check whether fLiteral.ch is null instead. LM. 1228 if (defaultType!=null && (defaultType.equals("#REQUIRED") || 1229 defaultType.equals("#IMPLIED"))) { 1230 if (fDTDHandler != null){ 1231 fDTDHandler.attributeDecl(elName, name, type, enumr, 1232 defaultType, null, null, null); 1233 } 1234 if(nonValidatingMode){ 1235 nvGrammarInfo.attributeDecl(elName, name, type, enumr, 1236 defaultType, null, null, null); 1237 1238 } 1239 } 1240 else { 1241 if (fDTDHandler != null){ 1242 fDTDHandler.attributeDecl(elName, name, type, enumr, 1243 defaultType, fLiteral, fLiteral2, null); 1244 } 1245 if(nonValidatingMode){ 1246 nvGrammarInfo.attributeDecl(elName, name, type, enumr, 1247 defaultType, fLiteral, fLiteral2, null); 1248 } 1249 } 1250 skipSeparator(false, !scanningInternalSubset()); 1251 } 1252 1253 // call handler 1254 if (fDTDHandler != null) { 1255 fDTDHandler.endAttlist(null); 1256 } 1257 fMarkUpDepth--; 1258 fReportEntity = true; 1259 1260 } // scanAttlistDecl() 1261 1262 /** 1263 * Scans an attribute type definition 1264 * <p> 1265 * <pre> 1266 * [54] AttType ::= StringType | TokenizedType | EnumeratedType 1267 * [55] StringType ::= 'CDATA' 1268 * [56] TokenizedType ::= 'ID' 1269 * | 'IDREF' 1270 * | 'IDREFS' 1271 * | 'ENTITY' 1272 * | 'ENTITIES' 1273 * | 'NMTOKEN' 1274 * | 'NMTOKENS' 1275 * [57] EnumeratedType ::= NotationType | Enumeration 1276 * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')' 1277 * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')' 1278 * </pre> 1279 * <p> 1280 * <strong>Note:</strong> Called after scanning past '<!ATTLIST' 1281 * 1282 * @param elName The element type name this declaration is about. 1283 * @param atName The attribute name this declaration is about. 1284 */ 1285 private final String scanAttType(String elName, String atName) 1286 throws IOException, XNIException { 1287 1288 String type = null; 1289 fEnumerationCount = 0; 1290 /* 1291 * Watchout: the order here is important: when a string happens to 1292 * be a substring of another string, the longer one needs to be 1293 * looked for first!! 1294 */ 1295 if (fEntityScanner.skipString("CDATA")) { 1296 type = "CDATA"; 1297 } 1298 else if (fEntityScanner.skipString("IDREFS")) { 1299 type = "IDREFS"; 1300 } 1301 else if (fEntityScanner.skipString("IDREF")) { 1302 type = "IDREF"; 1303 } 1304 else if (fEntityScanner.skipString("ID")) { 1305 type = "ID"; 1306 } 1307 else if (fEntityScanner.skipString("ENTITY")) { 1308 type = "ENTITY"; 1309 } 1310 else if (fEntityScanner.skipString("ENTITIES")) { 1311 type = "ENTITIES"; 1312 } 1313 else if (fEntityScanner.skipString("NMTOKENS")) { 1314 type = "NMTOKENS"; 1315 } 1316 else if (fEntityScanner.skipString("NMTOKEN")) { 1317 type = "NMTOKEN"; 1318 } 1319 else if (fEntityScanner.skipString("NOTATION")) { 1320 type = "NOTATION"; 1321 // spaces 1322 if (!skipSeparator(true, !scanningInternalSubset())) { 1323 reportFatalError("MSG_SPACE_REQUIRED_AFTER_NOTATION_IN_NOTATIONTYPE", 1324 new Object[]{elName, atName}); 1325 } 1326 // open paren 1327 int c = fEntityScanner.scanChar(); 1328 if (c != '(') { 1329 reportFatalError("MSG_OPEN_PAREN_REQUIRED_IN_NOTATIONTYPE", 1330 new Object[]{elName, atName}); 1331 } 1332 fMarkUpDepth++; 1333 do { 1334 skipSeparator(false, !scanningInternalSubset()); 1335 String aName = fEntityScanner.scanName(); 1336 if (aName == null) { 1337 reportFatalError("MSG_NAME_REQUIRED_IN_NOTATIONTYPE", 1338 new Object[]{elName, atName}); 1339 } 1340 ensureEnumerationSize(fEnumerationCount + 1); 1341 fEnumeration[fEnumerationCount++] = aName; 1342 skipSeparator(false, !scanningInternalSubset()); 1343 c = fEntityScanner.scanChar(); 1344 } while (c == '|'); 1345 if (c != ')') { 1346 reportFatalError("NotationTypeUnterminated", 1347 new Object[]{elName, atName}); 1348 } 1349 fMarkUpDepth--; 1350 } 1351 else { // Enumeration 1352 type = "ENUMERATION"; 1353 // open paren 1354 int c = fEntityScanner.scanChar(); 1355 if (c != '(') { 1356 // "OPEN_PAREN_REQUIRED_BEFORE_ENUMERATION_IN_ATTRDECL", 1357 reportFatalError("AttTypeRequiredInAttDef", 1358 new Object[]{elName, atName}); 1359 } 1360 fMarkUpDepth++; 1361 do { 1362 skipSeparator(false, !scanningInternalSubset()); 1363 String token = fEntityScanner.scanNmtoken(); 1364 if (token == null) { 1365 reportFatalError("MSG_NMTOKEN_REQUIRED_IN_ENUMERATION", 1366 new Object[]{elName, atName}); 1367 } 1368 ensureEnumerationSize(fEnumerationCount + 1); 1369 fEnumeration[fEnumerationCount++] = token; 1370 skipSeparator(false, !scanningInternalSubset()); 1371 c = fEntityScanner.scanChar(); 1372 } while (c == '|'); 1373 if (c != ')') { 1374 reportFatalError("EnumerationUnterminated", 1375 new Object[]{elName, atName}); 1376 } 1377 fMarkUpDepth--; 1378 } 1379 return type; 1380 1381 } // scanAttType():String 1382 1383 1384 /** 1385 * Scans an attribute default declaration 1386 * <p> 1387 * <pre> 1388 * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue) 1389 * </pre> 1390 * 1391 * @param name The name of the attribute being scanned. 1392 * @param defaultVal The string to fill in with the default value. 1393 */ 1394 protected final String scanAttDefaultDecl(String elName, String atName, 1395 String type, 1396 XMLString defaultVal, 1397 XMLString nonNormalizedDefaultVal) 1398 throws IOException, XNIException { 1399 1400 String defaultType = null; 1401 fString.clear(); 1402 defaultVal.clear(); 1403 if (fEntityScanner.skipString("#REQUIRED")) { 1404 defaultType = "#REQUIRED"; 1405 } 1406 else if (fEntityScanner.skipString("#IMPLIED")) { 1407 defaultType = "#IMPLIED"; 1408 } 1409 else { 1410 if (fEntityScanner.skipString("#FIXED")) { 1411 defaultType = "#FIXED"; 1412 // spaces 1413 if (!skipSeparator(true, !scanningInternalSubset())) { 1414 reportFatalError("MSG_SPACE_REQUIRED_AFTER_FIXED_IN_DEFAULTDECL", 1415 new Object[]{elName, atName}); 1416 } 1417 } 1418 // AttValue 1419 boolean isVC = !fStandalone && (fSeenExternalDTD || fSeenExternalPE) ; 1420 scanAttributeValue(defaultVal, nonNormalizedDefaultVal, atName, 1421 fAttributes, 0, isVC); 1422 } 1423 return defaultType; 1424 1425 } // ScanAttDefaultDecl 1426 1427 /** 1428 * Scans an entity declaration 1429 * <p> 1430 * <pre> 1431 * [70] EntityDecl ::= GEDecl | PEDecl 1432 * [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>' 1433 * [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>' 1434 * [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?) 1435 * [74] PEDef ::= EntityValue | ExternalID 1436 * [75] ExternalID ::= 'SYSTEM' S SystemLiteral 1437 * | 'PUBLIC' S PubidLiteral S SystemLiteral 1438 * [76] NDataDecl ::= S 'NDATA' S Name 1439 * </pre> 1440 * <p> 1441 * <strong>Note:</strong> Called after scanning past '<!ENTITY' 1442 */ 1443 private final void scanEntityDecl() throws IOException, XNIException { 1444 1445 boolean isPEDecl = false; 1446 boolean sawPERef = false; 1447 fReportEntity = false; 1448 if (fEntityScanner.skipSpaces()) { 1449 if (!fEntityScanner.skipChar('%')) { 1450 isPEDecl = false; // <!ENTITY x "x"> 1451 } 1452 else if (skipSeparator(true, !scanningInternalSubset())) { 1453 // <!ENTITY % x "x"> 1454 isPEDecl = true; 1455 } 1456 else if (scanningInternalSubset()) { 1457 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL", 1458 null); 1459 isPEDecl = true; 1460 } 1461 else if (fEntityScanner.peekChar() == '%') { 1462 // <!ENTITY %%x; "x"> is legal 1463 skipSeparator(false, !scanningInternalSubset()); 1464 isPEDecl = true; 1465 } 1466 else { 1467 sawPERef = true; 1468 } 1469 } 1470 else if (scanningInternalSubset() || !fEntityScanner.skipChar('%')) { 1471 // <!ENTITY[^ ]...> or <!ENTITY[^ %]...> 1472 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL", 1473 null); 1474 isPEDecl = false; 1475 } 1476 else if (fEntityScanner.skipSpaces()) { 1477 // <!ENTITY% ...> 1478 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_PERCENT_IN_PEDECL", 1479 null); 1480 isPEDecl = false; 1481 } 1482 else { 1483 sawPERef = true; 1484 } 1485 if (sawPERef) { 1486 while (true) { 1487 String peName = fEntityScanner.scanName(); 1488 if (peName == null) { 1489 reportFatalError("NameRequiredInPEReference", null); 1490 } 1491 else if (!fEntityScanner.skipChar(';')) { 1492 reportFatalError("SemicolonRequiredInPEReference", 1493 new Object[]{peName}); 1494 } 1495 else { 1496 startPE(peName, false); 1497 } 1498 fEntityScanner.skipSpaces(); 1499 if (!fEntityScanner.skipChar('%')) 1500 break; 1501 if (!isPEDecl) { 1502 if (skipSeparator(true, !scanningInternalSubset())) { 1503 isPEDecl = true; 1504 break; 1505 } 1506 isPEDecl = fEntityScanner.skipChar('%'); 1507 } 1508 } 1509 } 1510 1511 // name 1512 String name = fEntityScanner.scanName(); 1513 if (name == null) { 1514 reportFatalError("MSG_ENTITY_NAME_REQUIRED_IN_ENTITYDECL", null); 1515 } 1516 1517 // spaces 1518 if (!skipSeparator(true, !scanningInternalSubset())) { 1519 reportFatalError("MSG_SPACE_REQUIRED_AFTER_ENTITY_NAME_IN_ENTITYDECL", 1520 new Object[]{name}); 1521 } 1522 1523 // external id 1524 scanExternalID(fStrings, false); 1525 String systemId = fStrings[0]; 1526 String publicId = fStrings[1]; 1527 1528 if (isPEDecl && systemId != null) { 1529 fSeenExternalPE = true; 1530 } 1531 1532 String notation = null; 1533 // NDATA 1534 boolean sawSpace = skipSeparator(true, !scanningInternalSubset()); 1535 if (!isPEDecl && fEntityScanner.skipString("NDATA")) { 1536 // check whether there was space before NDATA 1537 if (!sawSpace) { 1538 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NDATA_IN_UNPARSED_ENTITYDECL", 1539 new Object[]{name}); 1540 } 1541 1542 // spaces 1543 if (!skipSeparator(true, !scanningInternalSubset())) { 1544 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_UNPARSED_ENTITYDECL", 1545 new Object[]{name}); 1546 } 1547 notation = fEntityScanner.scanName(); 1548 if (notation == null) { 1549 reportFatalError("MSG_NOTATION_NAME_REQUIRED_FOR_UNPARSED_ENTITYDECL", 1550 new Object[]{name}); 1551 } 1552 } 1553 1554 // internal entity 1555 if (systemId == null) { 1556 scanEntityValue(name, isPEDecl, fLiteral, fLiteral2); 1557 // since we need it's value anyway, let's snag it so it doesn't get corrupted 1558 // if a new load takes place before we store the entity values 1559 fStringBuffer.clear(); 1560 fStringBuffer2.clear(); 1561 fStringBuffer.append(fLiteral.ch, fLiteral.offset, fLiteral.length); 1562 fStringBuffer2.append(fLiteral2.ch, fLiteral2.offset, fLiteral2.length); 1563 } 1564 1565 // skip possible trailing space 1566 skipSeparator(false, !scanningInternalSubset()); 1567 1568 // end 1569 if (!fEntityScanner.skipChar('>')) { 1570 reportFatalError("EntityDeclUnterminated", new Object[]{name}); 1571 } 1572 fMarkUpDepth--; 1573 1574 // register entity and make callback 1575 if (isPEDecl) { 1576 name = "%" + name; 1577 } 1578 if (systemId != null) { 1579 String baseSystemId = fEntityScanner.getBaseSystemId(); 1580 if (notation != null) { 1581 fEntityStore.addUnparsedEntity(name, publicId, systemId, baseSystemId, notation); 1582 } 1583 else { 1584 fEntityStore.addExternalEntity(name, publicId, systemId, 1585 baseSystemId); 1586 } 1587 if (fDTDHandler != null) { 1588 //Venu Revisit : why false has been removed in expandSYstem 1589 fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId )); 1590 1591 if (notation != null) { 1592 fDTDHandler.unparsedEntityDecl(name, fResourceIdentifier, 1593 notation, null); 1594 } 1595 else { 1596 fDTDHandler.externalEntityDecl(name, fResourceIdentifier, null); 1597 } 1598 } 1599 } 1600 else { 1601 fEntityStore.addInternalEntity(name, fStringBuffer.toString()); 1602 if (fDTDHandler != null) { 1603 fDTDHandler.internalEntityDecl(name, fStringBuffer, fStringBuffer2, null); 1604 } 1605 } 1606 fReportEntity = true; 1607 1608 } // scanEntityDecl() 1609 1610 /** 1611 * Scans an entity value. 1612 * 1613 * @param value The string to fill in with the value. 1614 * @param nonNormalizedValue The string to fill in with the 1615 * non-normalized value. 1616 * 1617 * <strong>Note:</strong> This method uses fString, fStringBuffer (through 1618 * the use of scanCharReferenceValue), and fStringBuffer2, anything in them 1619 * at the time of calling is lost. 1620 */ 1621 protected final void scanEntityValue(String entityName, boolean isPEDecl, XMLString value, 1622 XMLString nonNormalizedValue) 1623 throws IOException, XNIException { 1624 int quote = fEntityScanner.scanChar(); 1625 if (quote != '\'' && quote != '"') { 1626 reportFatalError("OpenQuoteMissingInDecl", null); 1627 } 1628 // store at which depth of entities we start 1629 int entityDepth = fEntityDepth; 1630 1631 XMLString literal = fString; 1632 XMLString literal2 = fString; 1633 int countChar = 0; 1634 if (fLimitAnalyzer == null ) { 1635 fLimitAnalyzer = new XMLLimitAnalyzer(); 1636 } 1637 fLimitAnalyzer.startEntity(entityName); 1638 1639 if (fEntityScanner.scanLiteral(quote, fString) != quote) { 1640 fStringBuffer.clear(); 1641 fStringBuffer2.clear(); 1642 do { 1643 if (isPEDecl && fLimitAnalyzer != null) { 1644 checkLimit("%" + entityName, fString.length + countChar); 1645 } 1646 countChar = 0; 1647 fStringBuffer.append(fString); 1648 fStringBuffer2.append(fString); 1649 if (fEntityScanner.skipChar('&')) { 1650 if (fEntityScanner.skipChar('#')) { 1651 fStringBuffer2.append("&#"); 1652 scanCharReferenceValue(fStringBuffer, fStringBuffer2); 1653 } 1654 else { 1655 fStringBuffer.append('&'); 1656 fStringBuffer2.append('&'); 1657 String eName = fEntityScanner.scanName(); 1658 if (eName == null) { 1659 reportFatalError("NameRequiredInReference", 1660 null); 1661 } 1662 else { 1663 fStringBuffer.append(eName); 1664 fStringBuffer2.append(eName); 1665 } 1666 if (!fEntityScanner.skipChar(';')) { 1667 reportFatalError("SemicolonRequiredInReference", 1668 new Object[]{eName}); 1669 } 1670 else { 1671 fStringBuffer.append(';'); 1672 fStringBuffer2.append(';'); 1673 } 1674 } 1675 } 1676 else if (fEntityScanner.skipChar('%')) { 1677 while (true) { 1678 fStringBuffer2.append('%'); 1679 String peName = fEntityScanner.scanName(); 1680 if (peName == null) { 1681 reportFatalError("NameRequiredInPEReference", 1682 null); 1683 } 1684 else if (!fEntityScanner.skipChar(';')) { 1685 reportFatalError("SemicolonRequiredInPEReference", 1686 new Object[]{peName}); 1687 } 1688 else { 1689 if (scanningInternalSubset()) { 1690 reportFatalError("PEReferenceWithinMarkup", 1691 new Object[]{peName}); 1692 } 1693 fStringBuffer2.append(peName); 1694 fStringBuffer2.append(';'); 1695 } 1696 startPE(peName, true); 1697 // REVISIT: [Q] Why do we skip spaces here? -Ac 1698 // REVISIT: This will make returning the non- 1699 // normalized value harder. -Ac 1700 fEntityScanner.skipSpaces(); 1701 if (!fEntityScanner.skipChar('%')) 1702 break; 1703 } 1704 } 1705 else { 1706 countChar++; 1707 int c = fEntityScanner.peekChar(); 1708 if (XMLChar.isHighSurrogate(c)) { 1709 scanSurrogates(fStringBuffer2); 1710 } 1711 else if (isInvalidLiteral(c)) { 1712 reportFatalError("InvalidCharInLiteral", 1713 new Object[]{Integer.toHexString(c)}); 1714 fEntityScanner.scanChar(); 1715 } 1716 // if it's not the delimiting quote or if it is but from a 1717 // different entity than the one this literal started from, 1718 // simply append the character to our buffer 1719 else if (c != quote || entityDepth != fEntityDepth) { 1720 fStringBuffer.append((char)c); 1721 fStringBuffer2.append((char)c); 1722 fEntityScanner.scanChar(); 1723 } 1724 } 1725 } while (fEntityScanner.scanLiteral(quote, fString) != quote); 1726 fStringBuffer.append(fString); 1727 fStringBuffer2.append(fString); 1728 literal = fStringBuffer; 1729 literal2 = fStringBuffer2; 1730 } else { 1731 if (isPEDecl) { 1732 checkLimit("%" + entityName, literal); 1733 } 1734 } 1735 value.setValues(literal); 1736 nonNormalizedValue.setValues(literal2); 1737 if (fLimitAnalyzer != null) { 1738 fLimitAnalyzer.endEntity(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, entityName); 1739 } 1740 1741 if (!fEntityScanner.skipChar(quote)) { 1742 reportFatalError("CloseQuoteMissingInDecl", null); 1743 } 1744 } // scanEntityValue(XMLString,XMLString):void 1745 1746 /** 1747 * Scans a notation declaration 1748 * <p> 1749 * <pre> 1750 * [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID|PublicID) S? '>' 1751 * [83] PublicID ::= 'PUBLIC' S PubidLiteral 1752 * </pre> 1753 * <p> 1754 * <strong>Note:</strong> Called after scanning past '<!NOTATION' 1755 */ 1756 private final void scanNotationDecl() throws IOException, XNIException { 1757 1758 // spaces 1759 fReportEntity = false; 1760 if (!skipSeparator(true, !scanningInternalSubset())) { 1761 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_NOTATIONDECL", 1762 null); 1763 } 1764 1765 // notation name 1766 String name = fEntityScanner.scanName(); 1767 if (name == null) { 1768 reportFatalError("MSG_NOTATION_NAME_REQUIRED_IN_NOTATIONDECL", 1769 null); 1770 } 1771 1772 // spaces 1773 if (!skipSeparator(true, !scanningInternalSubset())) { 1774 reportFatalError("MSG_SPACE_REQUIRED_AFTER_NOTATION_NAME_IN_NOTATIONDECL", 1775 new Object[]{name}); 1776 } 1777 1778 // external id 1779 scanExternalID(fStrings, true); 1780 String systemId = fStrings[0]; 1781 String publicId = fStrings[1]; 1782 String baseSystemId = fEntityScanner.getBaseSystemId(); 1783 1784 if (systemId == null && publicId == null) { 1785 reportFatalError("ExternalIDorPublicIDRequired", 1786 new Object[]{name}); 1787 } 1788 1789 // skip possible trailing space 1790 skipSeparator(false, !scanningInternalSubset()); 1791 1792 // end 1793 if (!fEntityScanner.skipChar('>')) { 1794 reportFatalError("NotationDeclUnterminated", new Object[]{name}); 1795 } 1796 fMarkUpDepth--; 1797 1798 fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId )); 1799 if (nonValidatingMode) nvGrammarInfo.notationDecl(name, fResourceIdentifier, null); 1800 // call handler 1801 if (fDTDHandler != null) { 1802 //Venu Revisit wby false has been removed. 1803 //fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId, false)); 1804 fDTDHandler.notationDecl(name, fResourceIdentifier, null); 1805 } 1806 fReportEntity = true; 1807 1808 } // scanNotationDecl() 1809 1810 /** 1811 * Scans a conditional section. If it's a section to ignore the whole 1812 * section gets scanned through and this method only returns after the 1813 * closing bracket has been found. When it's an include section though, it 1814 * returns to let the main loop take care of scanning it. In that case the 1815 * end of the section if handled by the main loop (scanDecls). 1816 * <p> 1817 * <pre> 1818 * [61] conditionalSect ::= includeSect | ignoreSect 1819 * [62] includeSect ::= '<![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>' 1820 * [63] ignoreSect ::= '<![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>' 1821 * [64] ignoreSectContents ::= Ignore ('<![' ignoreSectContents ']]>' Ignore)* 1822 * [65] Ignore ::= Char* - (Char* ('<![' | ']]>') Char*) 1823 * </pre> 1824 * <p> 1825 * <strong>Note:</strong> Called after scanning past '<![' */ 1826 private final void scanConditionalSect(int currPEDepth) 1827 throws IOException, XNIException { 1828 1829 fReportEntity = false; 1830 skipSeparator(false, !scanningInternalSubset()); 1831 1832 if (fEntityScanner.skipString("INCLUDE")) { 1833 skipSeparator(false, !scanningInternalSubset()); 1834 if(currPEDepth != fPEDepth && fValidation) { 1835 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1836 "INVALID_PE_IN_CONDITIONAL", 1837 new Object[]{ fEntityManager.fCurrentEntity.name}, 1838 XMLErrorReporter.SEVERITY_ERROR); 1839 } 1840 // call handler 1841 if (!fEntityScanner.skipChar('[')) { 1842 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null); 1843 } 1844 1845 if (fDTDHandler != null) { 1846 fDTDHandler.startConditional(XMLDTDHandler.CONDITIONAL_INCLUDE, 1847 null); 1848 } 1849 fIncludeSectDepth++; 1850 // just stop there and go back to the main loop 1851 fReportEntity = true; 1852 } 1853 else if (fEntityScanner.skipString("IGNORE")) { 1854 skipSeparator(false, !scanningInternalSubset()); 1855 if(currPEDepth != fPEDepth && fValidation) { 1856 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1857 "INVALID_PE_IN_CONDITIONAL", 1858 new Object[]{ fEntityManager.fCurrentEntity.name}, 1859 XMLErrorReporter.SEVERITY_ERROR); 1860 } 1861 // call handler 1862 if (fDTDHandler != null) { 1863 fDTDHandler.startConditional(XMLDTDHandler.CONDITIONAL_IGNORE, 1864 null); 1865 } 1866 if (!fEntityScanner.skipChar('[')) { 1867 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null); 1868 } 1869 fReportEntity = true; 1870 int initialDepth = ++fIncludeSectDepth; 1871 if (fDTDHandler != null) { 1872 fIgnoreConditionalBuffer.clear(); 1873 } 1874 while (true) { 1875 if (fEntityScanner.skipChar('<')) { 1876 if (fDTDHandler != null) { 1877 fIgnoreConditionalBuffer.append('<'); 1878 } 1879 // 1880 // These tests are split so that we handle cases like 1881 // '<<![' and '<!<![' which we might otherwise miss. 1882 // 1883 if (fEntityScanner.skipChar('!')) { 1884 if(fEntityScanner.skipChar('[')) { 1885 if (fDTDHandler != null) { 1886 fIgnoreConditionalBuffer.append("!["); 1887 } 1888 fIncludeSectDepth++; 1889 } else { 1890 if (fDTDHandler != null) { 1891 fIgnoreConditionalBuffer.append("!"); 1892 } 1893 } 1894 } 1895 } 1896 else if (fEntityScanner.skipChar(']')) { 1897 if (fDTDHandler != null) { 1898 fIgnoreConditionalBuffer.append(']'); 1899 } 1900 // 1901 // The same thing goes for ']<![' and '<]]>', etc. 1902 // 1903 if (fEntityScanner.skipChar(']')) { 1904 if (fDTDHandler != null) { 1905 fIgnoreConditionalBuffer.append(']'); 1906 } 1907 while (fEntityScanner.skipChar(']')) { 1908 /* empty loop body */ 1909 if (fDTDHandler != null) { 1910 fIgnoreConditionalBuffer.append(']'); 1911 } 1912 } 1913 if (fEntityScanner.skipChar('>')) { 1914 if (fIncludeSectDepth-- == initialDepth) { 1915 fMarkUpDepth--; 1916 // call handler 1917 if (fDTDHandler != null) { 1918 fLiteral.setValues(fIgnoreConditionalBuffer.ch, 0, 1919 fIgnoreConditionalBuffer.length - 2); 1920 fDTDHandler.ignoredCharacters(fLiteral, null); 1921 fDTDHandler.endConditional(null); 1922 } 1923 return; 1924 } else if(fDTDHandler != null) { 1925 fIgnoreConditionalBuffer.append('>'); 1926 } 1927 } 1928 } 1929 } 1930 else { 1931 int c = fEntityScanner.scanChar(); 1932 if (fScannerState == SCANNER_STATE_END_OF_INPUT) { 1933 reportFatalError("IgnoreSectUnterminated", null); 1934 return; 1935 } 1936 if (fDTDHandler != null) { 1937 fIgnoreConditionalBuffer.append((char)c); 1938 } 1939 } 1940 } 1941 } 1942 else { 1943 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null); 1944 } 1945 1946 } // scanConditionalSect() 1947 1948 /** 1949 * Dispatch an XML "event". 1950 * 1951 * @param complete True if this method is intended to scan 1952 * and dispatch as much as possible. 1953 * 1954 * @return True if there is more to scan. 1955 * 1956 * @throws IOException Thrown on i/o error. 1957 * @throws XNIException Thrown on parse error. 1958 * 1959 */ 1960 protected final boolean scanDecls(boolean complete) 1961 throws IOException, XNIException { 1962 1963 skipSeparator(false, true); 1964 boolean again = true; 1965 //System.out.println("scanDecls"+fScannerState); 1966 while (again && fScannerState == SCANNER_STATE_MARKUP_DECL) { 1967 again = complete; 1968 if (fEntityScanner.skipChar('<')) { 1969 fMarkUpDepth++; 1970 if (fEntityScanner.skipChar('?')) { 1971 fStringBuffer.clear(); 1972 scanPI(fStringBuffer); 1973 fMarkUpDepth--; // we're done with this decl 1974 } 1975 else if (fEntityScanner.skipChar('!')) { 1976 if (fEntityScanner.skipChar('-')) { 1977 if (!fEntityScanner.skipChar('-')) { 1978 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", 1979 null); 1980 } else { 1981 scanComment(); 1982 } 1983 } 1984 else if (fEntityScanner.skipString("ELEMENT")) { 1985 scanElementDecl(); 1986 } 1987 else if (fEntityScanner.skipString("ATTLIST")) { 1988 scanAttlistDecl(); 1989 } 1990 else if (fEntityScanner.skipString("ENTITY")) { 1991 scanEntityDecl(); 1992 } 1993 else if (fEntityScanner.skipString("NOTATION")) { 1994 scanNotationDecl(); 1995 } 1996 else if (fEntityScanner.skipChar('[') && 1997 !scanningInternalSubset()) { 1998 scanConditionalSect(fPEDepth); 1999 } 2000 else { 2001 fMarkUpDepth--; 2002 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", 2003 null); 2004 } 2005 } 2006 else { 2007 fMarkUpDepth--; 2008 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null); 2009 } 2010 } 2011 else if (fIncludeSectDepth > 0 && fEntityScanner.skipChar(']')) { 2012 // end of conditional section? 2013 if (!fEntityScanner.skipChar(']') 2014 || !fEntityScanner.skipChar('>')) { 2015 reportFatalError("IncludeSectUnterminated", null); 2016 } 2017 // call handler 2018 if (fDTDHandler != null) { 2019 fDTDHandler.endConditional(null); 2020 } 2021 // decreaseMarkupDepth(); 2022 fIncludeSectDepth--; 2023 fMarkUpDepth--; 2024 } 2025 else if (scanningInternalSubset() && 2026 fEntityScanner.peekChar() == ']') { 2027 // this is the end of the internal subset, let's stop here 2028 return false; 2029 } 2030 else if (fEntityScanner.skipSpaces()) { 2031 // simply skip 2032 } 2033 else { 2034 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null); 2035 } 2036 skipSeparator(false, true); 2037 } 2038 return fScannerState != SCANNER_STATE_END_OF_INPUT; 2039 } 2040 2041 /** 2042 * Skip separator. This is typically just whitespace but it can also be one 2043 * or more parameter entity references. 2044 * <p> 2045 * If there are some it "expands them" by calling the corresponding entity 2046 * from the entity manager. 2047 * <p> 2048 * This is recursive and will process has many refs as possible. 2049 * 2050 * @param spaceRequired Specify whether some leading whitespace should be 2051 * found 2052 * @param lookForPERefs Specify whether parameter entity references should 2053 * be looked for 2054 * @return True if any leading whitespace was found or the end of a 2055 * parameter entity was crossed. 2056 */ 2057 private boolean skipSeparator(boolean spaceRequired, boolean lookForPERefs) 2058 throws IOException, XNIException { 2059 int depth = fPEDepth; 2060 boolean sawSpace = fEntityScanner.skipSpaces(); 2061 if (!lookForPERefs || !fEntityScanner.skipChar('%')) { 2062 return !spaceRequired || sawSpace || (depth != fPEDepth); 2063 } 2064 while (true) { 2065 String name = fEntityScanner.scanName(); 2066 if (name == null) { 2067 reportFatalError("NameRequiredInPEReference", null); 2068 } 2069 else if (!fEntityScanner.skipChar(';')) { 2070 reportFatalError("SemicolonRequiredInPEReference", 2071 new Object[]{name}); 2072 } 2073 startPE(name, false); 2074 fEntityScanner.skipSpaces(); 2075 if (!fEntityScanner.skipChar('%')) 2076 return true; 2077 } 2078 } 2079 2080 2081 /* 2082 * Element Children Content Stack 2083 */ 2084 private final void pushContentStack(int c) { 2085 if (fContentStack.length == fContentDepth) { 2086 int[] newStack = new int[fContentDepth * 2]; 2087 System.arraycopy(fContentStack, 0, newStack, 0, fContentDepth); 2088 fContentStack = newStack; 2089 } 2090 fContentStack[fContentDepth++] = c; 2091 } 2092 2093 private final int popContentStack() { 2094 return fContentStack[--fContentDepth]; 2095 } 2096 2097 2098 /* 2099 * Parameter Entity Stack 2100 */ 2101 private final void pushPEStack(int depth, boolean report) { 2102 if (fPEStack.length == fPEDepth) { 2103 int[] newIntStack = new int[fPEDepth * 2]; 2104 System.arraycopy(fPEStack, 0, newIntStack, 0, fPEDepth); 2105 fPEStack = newIntStack; 2106 // report end/start calls 2107 boolean[] newBooleanStack = new boolean[fPEDepth * 2]; 2108 System.arraycopy(fPEReport, 0, newBooleanStack, 0, fPEDepth); 2109 fPEReport = newBooleanStack; 2110 2111 } 2112 fPEReport[fPEDepth] = report; 2113 fPEStack[fPEDepth++] = depth; 2114 } 2115 2116 /** pop the stack */ 2117 private final int popPEStack() { 2118 return fPEStack[--fPEDepth]; 2119 } 2120 2121 /** look at the top of the stack */ 2122 private final boolean peekReportEntity() { 2123 return fPEReport[fPEDepth-1]; 2124 } 2125 2126 2127 /* 2128 * Utility method 2129 */ 2130 private final void ensureEnumerationSize(int size) { 2131 if (fEnumeration.length == size) { 2132 String[] newEnum = new String[size * 2]; 2133 System.arraycopy(fEnumeration, 0, newEnum, 0, size); 2134 fEnumeration = newEnum; 2135 } 2136 } 2137 2138 // private methods 2139 private void init() { 2140 // reset state related data 2141 fStartDTDCalled = false; 2142 fExtEntityDepth = 0; 2143 fIncludeSectDepth = 0; 2144 fMarkUpDepth = 0; 2145 fPEDepth = 0; 2146 2147 fStandalone = false; 2148 fSeenExternalDTD = false; 2149 fSeenExternalPE = false; 2150 2151 // set starting state 2152 setScannerState(SCANNER_STATE_TEXT_DECL); 2153 //new SymbolTable()); 2154 2155 fLimitAnalyzer = new XMLLimitAnalyzer(); 2156 } 2157 2158 /** 2159 * Add the count of the content buffer and check if the accumulated 2160 * value exceeds the limit 2161 * @param entityName entity name 2162 * @param buffer content buffer 2163 */ 2164 private void checkLimit(String entityName, XMLString buffer) { 2165 checkLimit(entityName, buffer.length); 2166 } 2167 2168 /** 2169 * Add the count and check limit 2170 * @param entityName entity name 2171 * @param len length of the buffer 2172 */ 2173 private void checkLimit(String entityName, int len) { 2174 if (fLimitAnalyzer == null) { 2175 fLimitAnalyzer = new XMLLimitAnalyzer(); 2176 } 2177 fLimitAnalyzer.addValue(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, entityName, len); 2178 if (fSecurityManager.isOverLimit(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, fLimitAnalyzer)) { 2179 fSecurityManager.debugPrint(fLimitAnalyzer); 2180 reportFatalError("MaxEntitySizeLimit", new Object[]{entityName, 2181 fLimitAnalyzer.getValue(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT), 2182 fSecurityManager.getLimit(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT), 2183 fSecurityManager.getStateLiteral(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT)}); 2184 } 2185 if (fSecurityManager.isOverLimit(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT, fLimitAnalyzer)) { 2186 fSecurityManager.debugPrint(fLimitAnalyzer); 2187 reportFatalError("TotalEntitySizeLimit", 2188 new Object[]{fLimitAnalyzer.getTotalValue(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT), 2189 fSecurityManager.getLimit(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT), 2190 fSecurityManager.getStateLiteral(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT)}); 2191 } 2192 2193 } 2194 2195 public DTDGrammar getGrammar(){ 2196 return nvGrammarInfo; 2197 } 2198 2199 } // class XMLDTDScannerImpl