1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 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.parsers; 23 24 import java.io.IOException; 25 26 import com.sun.org.apache.xerces.internal.impl.Constants; 27 import com.sun.org.apache.xerces.internal.util.EntityResolverWrapper; 28 import com.sun.org.apache.xerces.internal.util.EntityResolver2Wrapper; 29 import com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper; 30 import com.sun.org.apache.xerces.internal.util.SAXMessageFormatter; 31 import com.sun.org.apache.xerces.internal.util.Status; 32 import com.sun.org.apache.xerces.internal.util.SymbolTable; 33 import com.sun.org.apache.xerces.internal.utils.XMLSecurityManager; 34 import com.sun.org.apache.xerces.internal.utils.XMLSecurityPropertyManager; 35 import com.sun.org.apache.xerces.internal.xni.XNIException; 36 import com.sun.org.apache.xerces.internal.xni.grammars.XMLGrammarPool; 37 import com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; 38 import com.sun.org.apache.xerces.internal.xni.parser.XMLEntityResolver; 39 import com.sun.org.apache.xerces.internal.xni.parser.XMLErrorHandler; 40 import com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource; 41 import com.sun.org.apache.xerces.internal.xni.parser.XMLParseException; 42 import com.sun.org.apache.xerces.internal.xni.parser.XMLParserConfiguration; 43 import java.io.CharConversionException; 44 import org.w3c.dom.Node; 45 import org.xml.sax.EntityResolver; 46 import org.xml.sax.ErrorHandler; 47 import org.xml.sax.InputSource; 48 import org.xml.sax.SAXException; 49 import org.xml.sax.SAXNotRecognizedException; 50 import org.xml.sax.SAXNotSupportedException; 51 import org.xml.sax.SAXParseException; 52 import org.xml.sax.ext.EntityResolver2; 53 import org.xml.sax.helpers.LocatorImpl; 54 55 /** 56 * This is the main Xerces DOM parser class. It uses the abstract DOM 57 * parser with a document scanner, a dtd scanner, and a validator, as 58 * well as a grammar pool. 59 * 60 * @author Arnaud Le Hors, IBM 61 * @author Andy Clark, IBM 62 * 63 */ 64 public class DOMParser 65 extends AbstractDOMParser { 66 67 // 68 // Constants 69 // 70 71 // features 72 73 /** Feature identifier: EntityResolver2. */ 74 protected static final String USE_ENTITY_RESOLVER2 = 75 Constants.SAX_FEATURE_PREFIX + Constants.USE_ENTITY_RESOLVER2_FEATURE; 76 77 protected static final String REPORT_WHITESPACE = 78 Constants.SUN_SCHEMA_FEATURE_PREFIX + Constants.SUN_REPORT_IGNORED_ELEMENT_CONTENT_WHITESPACE; 79 80 /** Property identifier: Security property manager. */ 81 private static final String XML_SECURITY_PROPERTY_MANAGER = 82 Constants.XML_SECURITY_PROPERTY_MANAGER; 83 84 // recognized features: 85 private static final String[] RECOGNIZED_FEATURES = { 86 REPORT_WHITESPACE 87 }; 88 89 // properties 90 91 /** Property identifier: symbol table. */ 92 protected static final String SYMBOL_TABLE = 93 Constants.XERCES_PROPERTY_PREFIX + Constants.SYMBOL_TABLE_PROPERTY; 94 95 /** Property identifier: XML grammar pool. */ 96 protected static final String XMLGRAMMAR_POOL = 97 Constants.XERCES_PROPERTY_PREFIX+Constants.XMLGRAMMAR_POOL_PROPERTY; 98 99 /** Recognized properties. */ 100 private static final String[] RECOGNIZED_PROPERTIES = { 101 SYMBOL_TABLE, 102 XMLGRAMMAR_POOL, 103 }; 104 105 // 106 // Data 107 // 108 109 // features 110 111 /** Use EntityResolver2. */ 112 protected boolean fUseEntityResolver2 = true; 113 114 // 115 // Constructors 116 // 117 118 /** 119 * Constructs a DOM parser using the specified parser configuration. 120 */ DOMParser(XMLParserConfiguration config)121 public DOMParser(XMLParserConfiguration config) { 122 super(config); 123 } // <init>(XMLParserConfiguration) 124 125 /** 126 * Constructs a DOM parser using the dtd/xml schema parser configuration. 127 */ DOMParser()128 public DOMParser() { 129 this(null, null); 130 } // <init>() 131 132 /** 133 * Constructs a DOM parser using the specified symbol table. 134 */ DOMParser(SymbolTable symbolTable)135 public DOMParser(SymbolTable symbolTable) { 136 this(symbolTable, null); 137 } // <init>(SymbolTable) 138 139 140 /** 141 * Constructs a DOM parser using the specified symbol table and 142 * grammar pool. 143 */ DOMParser(SymbolTable symbolTable, XMLGrammarPool grammarPool)144 public DOMParser(SymbolTable symbolTable, XMLGrammarPool grammarPool) { 145 super(new XIncludeAwareParserConfiguration()); 146 147 // set properties 148 fConfiguration.addRecognizedProperties(RECOGNIZED_PROPERTIES); 149 if (symbolTable != null) { 150 fConfiguration.setProperty(SYMBOL_TABLE, symbolTable); 151 } 152 if (grammarPool != null) { 153 fConfiguration.setProperty(XMLGRAMMAR_POOL, grammarPool); 154 } 155 156 fConfiguration.addRecognizedFeatures(RECOGNIZED_FEATURES); 157 158 } // <init>(SymbolTable,XMLGrammarPool) 159 160 // 161 // XMLReader methods 162 // 163 164 /** 165 * Parses the input source specified by the given system identifier. 166 * <p> 167 * This method is equivalent to the following: 168 * <pre> 169 * parse(new InputSource(systemId)); 170 * </pre> 171 * 172 * @param systemId The system identifier (URI). 173 * 174 * @exception org.xml.sax.SAXException Throws exception on SAX error. 175 * @exception java.io.IOException Throws exception on i/o error. 176 */ parse(String systemId)177 public void parse(String systemId) throws SAXException, IOException { 178 179 // parse document 180 XMLInputSource source = new XMLInputSource(null, systemId, null, false); 181 try { 182 parse(source); 183 } 184 185 // wrap XNI exceptions as SAX exceptions 186 catch (XMLParseException e) { 187 Exception ex = e.getException(); 188 if (ex == null || ex instanceof CharConversionException) { 189 // must be a parser exception; mine it for locator info and throw 190 // a SAXParseException 191 LocatorImpl locatorImpl = new LocatorImpl(); 192 locatorImpl.setPublicId(e.getPublicId()); 193 locatorImpl.setSystemId(e.getExpandedSystemId()); 194 locatorImpl.setLineNumber(e.getLineNumber()); 195 locatorImpl.setColumnNumber(e.getColumnNumber()); 196 throw (ex == null) ? 197 new SAXParseException(e.getMessage(), locatorImpl) : 198 new SAXParseException(e.getMessage(), locatorImpl, ex); 199 } 200 if (ex instanceof SAXException) { 201 // why did we create an XMLParseException? 202 throw (SAXException)ex; 203 } 204 if (ex instanceof IOException) { 205 throw (IOException)ex; 206 } 207 throw new SAXException(ex); 208 } 209 catch (XNIException e) { 210 e.printStackTrace(); 211 Exception ex = e.getException(); 212 if (ex == null) { 213 throw new SAXException(e.getMessage()); 214 } 215 if (ex instanceof SAXException) { 216 throw (SAXException)ex; 217 } 218 if (ex instanceof IOException) { 219 throw (IOException)ex; 220 } 221 throw new SAXException(ex); 222 } 223 224 } // parse(String) 225 226 /** 227 * parse 228 * 229 * @param inputSource 230 * 231 * @exception org.xml.sax.SAXException 232 * @exception java.io.IOException 233 */ parse(InputSource inputSource)234 public void parse(InputSource inputSource) 235 throws SAXException, IOException { 236 237 // parse document 238 try { 239 XMLInputSource xmlInputSource = 240 new XMLInputSource(inputSource.getPublicId(), 241 inputSource.getSystemId(), 242 null, false); 243 xmlInputSource.setByteStream(inputSource.getByteStream()); 244 xmlInputSource.setCharacterStream(inputSource.getCharacterStream()); 245 xmlInputSource.setEncoding(inputSource.getEncoding()); 246 parse(xmlInputSource); 247 } 248 249 // wrap XNI exceptions as SAX exceptions 250 catch (XMLParseException e) { 251 Exception ex = e.getException(); 252 if (ex == null || ex instanceof CharConversionException) { 253 // must be a parser exception; mine it for locator info and throw 254 // a SAXParseException 255 LocatorImpl locatorImpl = new LocatorImpl(); 256 locatorImpl.setPublicId(e.getPublicId()); 257 locatorImpl.setSystemId(e.getExpandedSystemId()); 258 locatorImpl.setLineNumber(e.getLineNumber()); 259 locatorImpl.setColumnNumber(e.getColumnNumber()); 260 throw (ex == null) ? 261 new SAXParseException(e.getMessage(), locatorImpl) : 262 new SAXParseException(e.getMessage(), locatorImpl, ex); 263 } 264 if (ex instanceof SAXException) { 265 // why did we create an XMLParseException? 266 throw (SAXException)ex; 267 } 268 if (ex instanceof IOException) { 269 throw (IOException)ex; 270 } 271 throw new SAXException(ex); 272 } 273 catch (XNIException e) { 274 Exception ex = e.getException(); 275 if (ex == null) { 276 throw new SAXException(e.getMessage()); 277 } 278 if (ex instanceof SAXException) { 279 throw (SAXException)ex; 280 } 281 if (ex instanceof IOException) { 282 throw (IOException)ex; 283 } 284 throw new SAXException(ex); 285 } 286 287 } // parse(InputSource) 288 289 /** 290 * Sets the resolver used to resolve external entities. The EntityResolver 291 * interface supports resolution of public and system identifiers. 292 * 293 * @param resolver The new entity resolver. Passing a null value will 294 * uninstall the currently installed resolver. 295 */ setEntityResolver(EntityResolver resolver)296 public void setEntityResolver(EntityResolver resolver) { 297 298 try { 299 XMLEntityResolver xer = (XMLEntityResolver) fConfiguration.getProperty(ENTITY_RESOLVER); 300 if (fUseEntityResolver2 && resolver instanceof EntityResolver2) { 301 if (xer instanceof EntityResolver2Wrapper) { 302 EntityResolver2Wrapper er2w = (EntityResolver2Wrapper) xer; 303 er2w.setEntityResolver((EntityResolver2) resolver); 304 } 305 else { 306 fConfiguration.setProperty(ENTITY_RESOLVER, 307 new EntityResolver2Wrapper((EntityResolver2) resolver)); 308 } 309 } 310 else { 311 if (xer instanceof EntityResolverWrapper) { 312 EntityResolverWrapper erw = (EntityResolverWrapper) xer; 313 erw.setEntityResolver(resolver); 314 } 315 else { 316 fConfiguration.setProperty(ENTITY_RESOLVER, 317 new EntityResolverWrapper(resolver)); 318 } 319 } 320 } 321 catch (XMLConfigurationException e) { 322 // do nothing 323 } 324 325 } // setEntityResolver(EntityResolver) 326 327 /** 328 * Return the current entity resolver. 329 * 330 * @return The current entity resolver, or null if none 331 * has been registered. 332 * @see #setEntityResolver 333 */ getEntityResolver()334 public EntityResolver getEntityResolver() { 335 336 EntityResolver entityResolver = null; 337 try { 338 XMLEntityResolver xmlEntityResolver = 339 (XMLEntityResolver)fConfiguration.getProperty(ENTITY_RESOLVER); 340 if (xmlEntityResolver != null) { 341 if (xmlEntityResolver instanceof EntityResolverWrapper) { 342 entityResolver = 343 ((EntityResolverWrapper) xmlEntityResolver).getEntityResolver(); 344 } 345 else if (xmlEntityResolver instanceof EntityResolver2Wrapper) { 346 entityResolver = 347 ((EntityResolver2Wrapper) xmlEntityResolver).getEntityResolver(); 348 } 349 } 350 } 351 catch (XMLConfigurationException e) { 352 // do nothing 353 } 354 return entityResolver; 355 356 } // getEntityResolver():EntityResolver 357 358 /** 359 * Allow an application to register an error event handler. 360 * 361 * <p>If the application does not register an error handler, all 362 * error events reported by the SAX parser will be silently 363 * ignored; however, normal processing may not continue. It is 364 * highly recommended that all SAX applications implement an 365 * error handler to avoid unexpected bugs.</p> 366 * 367 * <p>Applications may register a new or different handler in the 368 * middle of a parse, and the SAX parser must begin using the new 369 * handler immediately.</p> 370 * 371 * @param errorHandler The error handler. 372 * @exception java.lang.NullPointerException If the handler 373 * argument is null. 374 * @see #getErrorHandler 375 */ setErrorHandler(ErrorHandler errorHandler)376 public void setErrorHandler(ErrorHandler errorHandler) { 377 378 try { 379 XMLErrorHandler xeh = (XMLErrorHandler) fConfiguration.getProperty(ERROR_HANDLER); 380 if (xeh instanceof ErrorHandlerWrapper) { 381 ErrorHandlerWrapper ehw = (ErrorHandlerWrapper) xeh; 382 ehw.setErrorHandler(errorHandler); 383 } 384 else { 385 fConfiguration.setProperty(ERROR_HANDLER, 386 new ErrorHandlerWrapper(errorHandler)); 387 } 388 } 389 catch (XMLConfigurationException e) { 390 // do nothing 391 } 392 393 } // setErrorHandler(ErrorHandler) 394 395 /** 396 * Return the current error handler. 397 * 398 * @return The current error handler, or null if none 399 * has been registered. 400 * @see #setErrorHandler 401 */ getErrorHandler()402 public ErrorHandler getErrorHandler() { 403 404 ErrorHandler errorHandler = null; 405 try { 406 XMLErrorHandler xmlErrorHandler = 407 (XMLErrorHandler)fConfiguration.getProperty(ERROR_HANDLER); 408 if (xmlErrorHandler != null && 409 xmlErrorHandler instanceof ErrorHandlerWrapper) { 410 errorHandler = ((ErrorHandlerWrapper)xmlErrorHandler).getErrorHandler(); 411 } 412 } 413 catch (XMLConfigurationException e) { 414 // do nothing 415 } 416 return errorHandler; 417 418 } // getErrorHandler():ErrorHandler 419 420 /** 421 * Set the state of any feature in a SAX2 parser. The parser 422 * might not recognize the feature, and if it does recognize 423 * it, it might not be able to fulfill the request. 424 * 425 * @param featureId The unique identifier (URI) of the feature. 426 * @param state The requested state of the feature (true or false). 427 * 428 * @exception SAXNotRecognizedException If the 429 * requested feature is not known. 430 * @exception SAXNotSupportedException If the 431 * requested feature is known, but the requested 432 * state is not supported. 433 */ setFeature(String featureId, boolean state)434 public void setFeature(String featureId, boolean state) 435 throws SAXNotRecognizedException, SAXNotSupportedException { 436 437 try { 438 439 // http://xml.org/sax/features/use-entity-resolver2 440 // controls whether the methods of an object implementing 441 // org.xml.sax.ext.EntityResolver2 will be used by the parser. 442 // 443 if (featureId.equals(USE_ENTITY_RESOLVER2)) { 444 if (state != fUseEntityResolver2) { 445 fUseEntityResolver2 = state; 446 // Refresh EntityResolver wrapper. 447 setEntityResolver(getEntityResolver()); 448 } 449 return; 450 } 451 452 // 453 // Default handling 454 // 455 456 fConfiguration.setFeature(featureId, state); 457 } 458 catch (XMLConfigurationException e) { 459 String identifier = e.getIdentifier(); 460 if (e.getType() == Status.NOT_RECOGNIZED) { 461 throw new SAXNotRecognizedException( 462 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), 463 "feature-not-recognized", new Object [] {identifier})); 464 } 465 else { 466 throw new SAXNotSupportedException( 467 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), 468 "feature-not-supported", new Object [] {identifier})); 469 } 470 } 471 472 } // setFeature(String,boolean) 473 474 /** 475 * Query the state of a feature. 476 * 477 * Query the current state of any feature in a SAX2 parser. The 478 * parser might not recognize the feature. 479 * 480 * @param featureId The unique identifier (URI) of the feature 481 * being set. 482 * @return The current state of the feature. 483 * @exception org.xml.sax.SAXNotRecognizedException If the 484 * requested feature is not known. 485 * @exception SAXNotSupportedException If the 486 * requested feature is known but not supported. 487 */ getFeature(String featureId)488 public boolean getFeature(String featureId) 489 throws SAXNotRecognizedException, SAXNotSupportedException { 490 491 try { 492 493 // http://xml.org/sax/features/use-entity-resolver2 494 // controls whether the methods of an object implementing 495 // org.xml.sax.ext.EntityResolver2 will be used by the parser. 496 // 497 if (featureId.equals(USE_ENTITY_RESOLVER2)) { 498 return fUseEntityResolver2; 499 } 500 501 // 502 // Default handling 503 // 504 505 return fConfiguration.getFeature(featureId); 506 } 507 catch (XMLConfigurationException e) { 508 String identifier = e.getIdentifier(); 509 if (e.getType() == Status.NOT_RECOGNIZED) { 510 throw new SAXNotRecognizedException( 511 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), 512 "feature-not-recognized", new Object [] {identifier})); 513 } 514 else { 515 throw new SAXNotSupportedException( 516 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), 517 "feature-not-supported", new Object [] {identifier})); 518 } 519 } 520 521 } // getFeature(String):boolean 522 523 /** 524 * Set the value of any property in a SAX2 parser. The parser 525 * might not recognize the property, and if it does recognize 526 * it, it might not support the requested value. 527 * 528 * @param propertyId The unique identifier (URI) of the property 529 * being set. 530 * @param value The value to which the property is being set. 531 * 532 * @exception SAXNotRecognizedException If the 533 * requested property is not known. 534 * @exception SAXNotSupportedException If the 535 * requested property is known, but the requested 536 * value is not supported. 537 */ setProperty(String propertyId, Object value)538 public void setProperty(String propertyId, Object value) 539 throws SAXNotRecognizedException, SAXNotSupportedException { 540 /** 541 * It's possible for users to set a security manager through the interface. 542 * If it's the old SecurityManager, convert it to the new XMLSecurityManager 543 */ 544 if (propertyId.equals(Constants.SECURITY_MANAGER)) { 545 securityManager = XMLSecurityManager.convert(value, securityManager); 546 setProperty0(Constants.SECURITY_MANAGER, securityManager); 547 return; 548 } 549 if (propertyId.equals(Constants.XML_SECURITY_PROPERTY_MANAGER)) { 550 if (value == null) { 551 securityPropertyManager = new XMLSecurityPropertyManager(); 552 } else { 553 securityPropertyManager = (XMLSecurityPropertyManager)value; 554 } 555 setProperty0(Constants.XML_SECURITY_PROPERTY_MANAGER, securityPropertyManager); 556 return; 557 } 558 559 if (securityManager == null) { 560 securityManager = new XMLSecurityManager(true); 561 setProperty0(Constants.SECURITY_MANAGER, securityManager); 562 } 563 564 if (securityPropertyManager == null) { 565 securityPropertyManager = new XMLSecurityPropertyManager(); 566 setProperty0(Constants.XML_SECURITY_PROPERTY_MANAGER, securityPropertyManager); 567 } 568 int index = securityPropertyManager.getIndex(propertyId); 569 570 if (index > -1) { 571 /** 572 * this is a direct call to this parser, not a subclass since 573 * internally the support of this property is done through 574 * XMLSecurityPropertyManager 575 */ 576 securityPropertyManager.setValue(index, XMLSecurityPropertyManager.State.APIPROPERTY, (String)value); 577 } else { 578 //check if the property is managed by security manager 579 if (!securityManager.setLimit(propertyId, XMLSecurityManager.State.APIPROPERTY, value)) { 580 //fall back to the default configuration to handle the property 581 setProperty0(propertyId, value); 582 } 583 } 584 } 585 setProperty0(String propertyId, Object value)586 public void setProperty0(String propertyId, Object value) 587 throws SAXNotRecognizedException, SAXNotSupportedException { 588 try { 589 fConfiguration.setProperty(propertyId, value); 590 } 591 catch (XMLConfigurationException e) { 592 String identifier = e.getIdentifier(); 593 if (e.getType() == Status.NOT_RECOGNIZED) { 594 throw new SAXNotRecognizedException( 595 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), 596 "property-not-recognized", new Object [] {identifier})); 597 } 598 else { 599 throw new SAXNotSupportedException( 600 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), 601 "property-not-supported", new Object [] {identifier})); 602 } 603 } 604 605 } // setProperty(String,Object) 606 607 /** 608 * Query the value of a property. 609 * 610 * Return the current value of a property in a SAX2 parser. 611 * The parser might not recognize the property. 612 * 613 * @param propertyId The unique identifier (URI) of the property 614 * being set. 615 * @return The current value of the property. 616 * @exception org.xml.sax.SAXNotRecognizedException If the 617 * requested property is not known. 618 * @exception SAXNotSupportedException If the 619 * requested property is known but not supported. 620 */ getProperty(String propertyId)621 public Object getProperty(String propertyId) 622 throws SAXNotRecognizedException, SAXNotSupportedException { 623 624 if (propertyId.equals(CURRENT_ELEMENT_NODE)) { 625 boolean deferred = false; 626 try { 627 deferred = getFeature(DEFER_NODE_EXPANSION); 628 } 629 catch (XMLConfigurationException e){ 630 // ignore 631 } 632 if (deferred) { 633 throw new SAXNotSupportedException("Current element node cannot be queried when node expansion is deferred."); 634 } 635 return (fCurrentNode!=null && 636 fCurrentNode.getNodeType() == Node.ELEMENT_NODE)? fCurrentNode:null; 637 } 638 639 try { 640 XMLSecurityPropertyManager spm = (XMLSecurityPropertyManager) 641 fConfiguration.getProperty(XML_SECURITY_PROPERTY_MANAGER); 642 int index = spm.getIndex(propertyId); 643 if (index > -1) { 644 return spm.getValueByIndex(index); 645 } 646 647 return fConfiguration.getProperty(propertyId); 648 } 649 catch (XMLConfigurationException e) { 650 String identifier = e.getIdentifier(); 651 if (e.getType() == Status.NOT_RECOGNIZED) { 652 throw new SAXNotRecognizedException( 653 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), 654 "property-not-recognized", new Object [] {identifier})); 655 } 656 else { 657 throw new SAXNotSupportedException( 658 SAXMessageFormatter.formatMessage(fConfiguration.getLocale(), 659 "property-not-supported", new Object [] {identifier})); 660 } 661 } 662 663 } // getProperty(String):Object 664 665 /** 666 * Returns this parser's XMLParserConfiguration. 667 */ getXMLParserConfiguration()668 public XMLParserConfiguration getXMLParserConfiguration() { 669 return fConfiguration; 670 } // getXMLParserConfiguration():XMLParserConfiguration 671 672 } // class DOMParser 673