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