XMLDTDScannerImpl.java revision 1031:63c9e5adcfc8
1240616Sjimharris/* 2253112Sjimharris * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. 3240616Sjimharris */ 4240616Sjimharris 5240616Sjimharris/* 6240616Sjimharris * Licensed to the Apache Software Foundation (ASF) under one or more 7240616Sjimharris * contributor license agreements. See the NOTICE file distributed with 8240616Sjimharris * this work for additional information regarding copyright ownership. 9240616Sjimharris * The ASF licenses this file to You under the Apache License, Version 2.0 10240616Sjimharris * (the "License"); you may not use this file except in compliance with 11240616Sjimharris * the License. You may obtain a copy of the License at 12240616Sjimharris * 13240616Sjimharris * http://www.apache.org/licenses/LICENSE-2.0 14240616Sjimharris * 15240616Sjimharris * Unless required by applicable law or agreed to in writing, software 16240616Sjimharris * distributed under the License is distributed on an "AS IS" BASIS, 17240616Sjimharris * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18240616Sjimharris * See the License for the specific language governing permissions and 19240616Sjimharris * limitations under the License. 20240616Sjimharris */ 21240616Sjimharris 22240616Sjimharrispackage com.sun.org.apache.xerces.internal.impl; 23240616Sjimharris 24240616Sjimharrisimport com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter; 25240616Sjimharrisimport com.sun.org.apache.xerces.internal.util.SymbolTable; 26240616Sjimharrisimport com.sun.org.apache.xerces.internal.util.XMLAttributesImpl; 27240616Sjimharrisimport com.sun.org.apache.xerces.internal.util.XMLChar; 28240616Sjimharrisimport com.sun.org.apache.xerces.internal.util.XMLStringBuffer; 29240616Sjimharrisimport com.sun.org.apache.xerces.internal.utils.XMLLimitAnalyzer; 30240616Sjimharrisimport com.sun.org.apache.xerces.internal.utils.XMLSecurityManager; 31240616Sjimharrisimport com.sun.org.apache.xerces.internal.xni.XMLDTDContentModelHandler; 32240616Sjimharrisimport com.sun.org.apache.xerces.internal.xni.XMLDTDHandler; 33248977Sjimharrisimport com.sun.org.apache.xerces.internal.xni.XMLResourceIdentifier; 34248773Sjimharrisimport com.sun.org.apache.xerces.internal.xni.XMLString; 35240616Sjimharrisimport com.sun.org.apache.xerces.internal.xni.XNIException; 36240616Sjimharrisimport com.sun.org.apache.xerces.internal.xni.parser.XMLComponent; 37240616Sjimharrisimport com.sun.org.apache.xerces.internal.xni.parser.XMLComponentManager; 38240616Sjimharrisimport com.sun.org.apache.xerces.internal.xni.parser.XMLConfigurationException; 39240616Sjimharrisimport com.sun.org.apache.xerces.internal.xni.parser.XMLDTDScanner; 40240616Sjimharrisimport com.sun.org.apache.xerces.internal.xni.parser.XMLInputSource; 41248748Sjimharrisimport com.sun.org.apache.xerces.internal.xni.Augmentations; 42240616Sjimharrisimport com.sun.xml.internal.stream.dtd.nonvalidating.DTDGrammar; 43241659Sjimharrisimport java.io.EOFException; 44241659Sjimharrisimport java.io.IOException; 45240616Sjimharris 46240616Sjimharris/** 47240616Sjimharris * This class is responsible for scanning the declarations found 48240616Sjimharris * in the internal and external subsets of a DTD in an XML document. 49240616Sjimharris * The scanner acts as the sources for the DTD information which is 50240616Sjimharris * communicated to the DTD handlers. 51240616Sjimharris * <p> 52240616Sjimharris * This component requires the following features and properties from the 53240616Sjimharris * component manager that uses it: 54240616Sjimharris * <ul> 55240616Sjimharris * <li>http://xml.org/sax/features/validation</li> 56240616Sjimharris * <li>http://apache.org/xml/features/scanner/notify-char-refs</li> 57240616Sjimharris * <li>http://apache.org/xml/properties/internal/symbol-table</li> 58240616Sjimharris * <li>http://apache.org/xml/properties/internal/error-reporter</li> 59240616Sjimharris * <li>http://apache.org/xml/properties/internal/entity-manager</li> 60243951Sjimharris * </ul> 61243951Sjimharris * 62240616Sjimharris * @author Arnaud Le Hors, IBM 63240616Sjimharris * @author Andy Clark, IBM 64240616Sjimharris * @author Glenn Marcy, IBM 65240616Sjimharris * @author Eric Ye, IBM 66240616Sjimharris * 67241658Sjimharris */ 68241658Sjimharrispublic class XMLDTDScannerImpl 69240616Sjimharrisextends XMLScanner 70252271Sjimharrisimplements XMLDTDScanner, XMLComponent, XMLEntityHandler { 71240616Sjimharris 72241664Sjimharris // 73240616Sjimharris // Constants 74240616Sjimharris // 75240616Sjimharris 76240616Sjimharris // scanner states 77240616Sjimharris 78240616Sjimharris /** Scanner state: end of input. */ 79241664Sjimharris protected static final int SCANNER_STATE_END_OF_INPUT = 0; 80241664Sjimharris 81241664Sjimharris /** Scanner state: text declaration. */ 82241664Sjimharris protected static final int SCANNER_STATE_TEXT_DECL = 1; 83241664Sjimharris 84241664Sjimharris /** Scanner state: markup declaration. */ 85241664Sjimharris protected static final int SCANNER_STATE_MARKUP_DECL = 2; 86241664Sjimharris 87241664Sjimharris // recognized features and properties 88248767Sjimharris 89241664Sjimharris /** Recognized features. */ 90241664Sjimharris private static final String[] RECOGNIZED_FEATURES = { 91241664Sjimharris VALIDATION, 92240616Sjimharris NOTIFY_CHAR_REFS, 93240616Sjimharris }; 94240616Sjimharris 95240616Sjimharris /** Feature defaults. */ 96240616Sjimharris private static final Boolean[] FEATURE_DEFAULTS = { 97240616Sjimharris null, 98240616Sjimharris Boolean.FALSE, 99240616Sjimharris }; 100240616Sjimharris 101248737Sjimharris /** Recognized properties. */ 102240616Sjimharris private static final String[] RECOGNIZED_PROPERTIES = { 103248755Sjimharris SYMBOL_TABLE, 104248749Sjimharris ERROR_REPORTER, 105248749Sjimharris ENTITY_MANAGER, 106240616Sjimharris }; 107248761Sjimharris 108248761Sjimharris /** Property defaults. */ 109248759Sjimharris private static final Object[] PROPERTY_DEFAULTS = { 110248759Sjimharris null, 111248759Sjimharris null, 112241433Sjimharris null, 113241433Sjimharris }; 114241433Sjimharris 115241433Sjimharris // debugging 116248977Sjimharris 117248977Sjimharris /** Debug scanner state. */ 118248977Sjimharris private static final boolean DEBUG_SCANNER_STATE = false; 119248977Sjimharris 120248977Sjimharris // 121248977Sjimharris // Data 122248977Sjimharris // 123248977Sjimharris 124248977Sjimharris // handlers 125248977Sjimharris 126248761Sjimharris /** DTD handler. */ 127248761Sjimharris public XMLDTDHandler fDTDHandler = null; 128241659Sjimharris 129248769Sjimharris /** DTD content model handler. */ 130248769Sjimharris protected XMLDTDContentModelHandler fDTDContentModelHandler; 131248769Sjimharris 132248769Sjimharris // state 133248769Sjimharris 134248769Sjimharris /** Scanner state. */ 135248913Sjimharris protected int fScannerState; 136248913Sjimharris 137248913Sjimharris /** Standalone. */ 138248977Sjimharris protected boolean fStandalone; 139248977Sjimharris 140248977Sjimharris /** Seen external DTD. */ 141248913Sjimharris protected boolean fSeenExternalDTD; 142241659Sjimharris 143241659Sjimharris /** Seen external parameter entity. */ 144241659Sjimharris protected boolean fSeenExternalPE; 145248767Sjimharris 146248913Sjimharris // private data 147248913Sjimharris 148248977Sjimharris /** Start DTD called. */ 149248913Sjimharris private boolean fStartDTDCalled; 150248913Sjimharris 151241659Sjimharris /** Default attribute */ 152248749Sjimharris private XMLAttributesImpl fAttributes = new XMLAttributesImpl(); 153241659Sjimharris 154241659Sjimharris /** 155248761Sjimharris * Stack of content operators (either '|' or ',') in children 156241665Sjimharris * content. 157241659Sjimharris */ 158241659Sjimharris private int[] fContentStack = new int[5]; 159248737Sjimharris 160248737Sjimharris /** Size of content stack. */ 161248737Sjimharris private int fContentDepth; 162248737Sjimharris 163248759Sjimharris /** Parameter entity stack to check well-formedness. */ 164248760Sjimharris private int[] fPEStack = new int[5]; 165248759Sjimharris 166248759Sjimharris 167248737Sjimharris /** Parameter entity stack to report start/end entity calls. */ 168248737Sjimharris private boolean[] fPEReport = new boolean[5]; 169240616Sjimharris 170240616Sjimharris /** Number of opened parameter entities. */ 171248741Sjimharris private int fPEDepth; 172241659Sjimharris 173240616Sjimharris /** Markup depth. */ 174240616Sjimharris private int fMarkUpDepth; 175241658Sjimharris 176240616Sjimharris /** Number of opened external entities. */ 177241658Sjimharris private int fExtEntityDepth; 178241658Sjimharris 179241658Sjimharris /** Number of opened include sections. */ 180241658Sjimharris private int fIncludeSectDepth; 181240616Sjimharris 182240616Sjimharris // temporary variables 183240616Sjimharris 184240616Sjimharris /** Array of 3 strings. */ 185240616Sjimharris private String[] fStrings = new String[3]; 186240616Sjimharris 187240616Sjimharris /** String. */ 188240616Sjimharris private XMLString fString = new XMLString(); 189240616Sjimharris 190240616Sjimharris /** String buffer. */ 191240616Sjimharris private XMLStringBuffer fStringBuffer = new XMLStringBuffer(); 192240616Sjimharris 193240616Sjimharris /** String buffer. */ 194240616Sjimharris private XMLStringBuffer fStringBuffer2 = new XMLStringBuffer(); 195241664Sjimharris 196240616Sjimharris /** Literal text. */ 197240616Sjimharris private XMLString fLiteral = new XMLString(); 198240616Sjimharris 199240616Sjimharris /** Literal text. */ 200240616Sjimharris private XMLString fLiteral2 = new XMLString(); 201240616Sjimharris 202240616Sjimharris /** Enumeration values. */ 203240616Sjimharris private String[] fEnumeration = new String[5]; 204241434Sjimharris 205240616Sjimharris /** Enumeration values count. */ 206240616Sjimharris private int fEnumerationCount; 207240616Sjimharris 208240616Sjimharris /** Ignore conditional section buffer. */ 209240616Sjimharris private XMLStringBuffer fIgnoreConditionalBuffer = new XMLStringBuffer(128); 210240616Sjimharris 211240616Sjimharris /** Object contains grammar information for a non-validaing parser. */ 212240616Sjimharris DTDGrammar nvGrammarInfo = null; 213240616Sjimharris 214240616Sjimharris boolean nonValidatingMode = false; 215240616Sjimharris // 216240616Sjimharris // Constructors 217248741Sjimharris // 218248741Sjimharris 219241665Sjimharris /** Default constructor. */ 220240616Sjimharris public XMLDTDScannerImpl() { 221240616Sjimharris } // <init>() 222240616Sjimharris 223248746Sjimharris /** Constructor for he use of non-XMLComponentManagers. */ 224248746Sjimharris public XMLDTDScannerImpl(SymbolTable symbolTable, 225241433Sjimharris XMLErrorReporter errorReporter, XMLEntityManager entityManager) { 226241433Sjimharris fSymbolTable = symbolTable; 227241433Sjimharris fErrorReporter = errorReporter; 228241433Sjimharris fEntityManager = entityManager; 229240616Sjimharris entityManager.setProperty(SYMBOL_TABLE, fSymbolTable); 230240616Sjimharris } 231240616Sjimharris 232240616Sjimharris // 233240616Sjimharris // XMLDTDScanner methods 234240616Sjimharris // 235240616Sjimharris 236248738Sjimharris /** 237249418Sjimharris * Sets the input source. 238240616Sjimharris * 239240616Sjimharris * @param inputSource The input source or null. 240240616Sjimharris * 241240616Sjimharris * @throws IOException Thrown on i/o error. 242240616Sjimharris */ 243240616Sjimharris public void setInputSource(XMLInputSource inputSource) throws IOException { 244240616Sjimharris if (inputSource == null) { 245240616Sjimharris // no system id was available 246240616Sjimharris if (fDTDHandler != null) { 247249417Sjimharris fDTDHandler.startDTD(null, null); 248249417Sjimharris fDTDHandler.endDTD(null); 249240616Sjimharris } 250240616Sjimharris if (nonValidatingMode){ 251240616Sjimharris nvGrammarInfo.startDTD(null,null); 252240616Sjimharris nvGrammarInfo.endDTD(null); 253240616Sjimharris } 254240616Sjimharris return; 255240616Sjimharris } 256244413Sjimharris fEntityManager.setEntityHandler(this); 257244413Sjimharris fEntityManager.startDTDEntity(inputSource); 258244413Sjimharris } // setInputSource(XMLInputSource) 259244413Sjimharris 260244413Sjimharris 261244413Sjimharris public void setLimitAnalyzer(XMLLimitAnalyzer limitAnalyzer) { 262244413Sjimharris fLimitAnalyzer = limitAnalyzer; 263244413Sjimharris } 264240616Sjimharris 265240616Sjimharris /** 266240616Sjimharris * Scans the external subset of the document. 267240616Sjimharris * 268240616Sjimharris * @param complete True if the scanner should scan the document 269240616Sjimharris * completely, pushing all events to the registered 270240616Sjimharris * document handler. A value of false indicates that 271240616Sjimharris * that the scanner should only scan the next portion 272240616Sjimharris * of the document and return. A scanner instance is 273248754Sjimharris * permitted to completely scan a document if it does 274240616Sjimharris * not support this "pull" scanning model. 275240616Sjimharris * 276240616Sjimharris * @return True if there is more to scan, false otherwise. 277240616Sjimharris */ 278240616Sjimharris public boolean scanDTDExternalSubset(boolean complete) 279240616Sjimharris throws IOException, XNIException { 280240616Sjimharris 281240616Sjimharris fEntityManager.setEntityHandler(this); 282248767Sjimharris if (fScannerState == SCANNER_STATE_TEXT_DECL) { 283248754Sjimharris fSeenExternalDTD = true; 284248767Sjimharris boolean textDecl = scanTextDecl(); 285248748Sjimharris if (fScannerState == SCANNER_STATE_END_OF_INPUT) { 286240616Sjimharris return false; 287240616Sjimharris } 288240616Sjimharris else { 289240616Sjimharris // next state is markup decls regardless of whether there 290240616Sjimharris // is a TextDecl or not 291240616Sjimharris setScannerState(SCANNER_STATE_MARKUP_DECL); 292240616Sjimharris if (textDecl && !complete) { 293240616Sjimharris return true; 294240616Sjimharris } 295240616Sjimharris } 296240616Sjimharris } 297240616Sjimharris // keep dispatching "events" 298248762Sjimharris do { 299248762Sjimharris if (!scanDecls(complete)) { 300248762Sjimharris return false; 301240616Sjimharris } 302240616Sjimharris } while (complete); 303240616Sjimharris 304240616Sjimharris // return that there is more to scan 305240616Sjimharris return true; 306240616Sjimharris 307248749Sjimharris } // scanDTDExternalSubset(boolean):boolean 308248749Sjimharris 309248749Sjimharris /** 310240616Sjimharris * Scans the internal subset of the document. 311240616Sjimharris * 312240616Sjimharris * @param complete True if the scanner should scan the document 313240616Sjimharris * completely, pushing all events to the registered 314240616Sjimharris * document handler. A value of false indicates that 315240616Sjimharris * that the scanner should only scan the next portion 316240616Sjimharris * of the document and return. A scanner instance is 317240616Sjimharris * permitted to completely scan a document if it does 318240616Sjimharris * not support this "pull" scanning model. 319240616Sjimharris * @param standalone True if the document was specified as standalone. 320248737Sjimharris * This value is important for verifying certain 321248737Sjimharris * well-formedness constraints. 322248737Sjimharris * @param hasExternalDTD True if the document has an external DTD. 323248738Sjimharris * This allows the scanner to properly notify 324248738Sjimharris * the handler of the end of the DTD in the 325248755Sjimharris * absence of an external subset. 326248755Sjimharris * 327248767Sjimharris * @return True if there is more to scan, false otherwise. 328248767Sjimharris */ 329248767Sjimharris public boolean scanDTDInternalSubset(boolean complete, boolean standalone, 330240616Sjimharris boolean hasExternalSubset) 331240616Sjimharris throws IOException, XNIException { 332240616Sjimharris // reset entity scanner 333240616Sjimharris //xxx:stax getText() is supposed to return only DTD internal subset 334240616Sjimharris //shouldn't we record position here before we go ahead ?? 335240616Sjimharris 336240616Sjimharris fEntityScanner = (XMLEntityScanner)fEntityManager.getEntityScanner(); 337240616Sjimharris fEntityManager.setEntityHandler(this); 338240616Sjimharris fStandalone = standalone; 339240616Sjimharris //System.out.println("state"+fScannerState); 340240616Sjimharris if (fScannerState == SCANNER_STATE_TEXT_DECL) { 341240616Sjimharris // call handler 342240616Sjimharris if (fDTDHandler != null) { 343240616Sjimharris fDTDHandler.startDTD(fEntityScanner, null); 344240616Sjimharris fStartDTDCalled = true; 345240616Sjimharris } 346240616Sjimharris 347240616Sjimharris if (nonValidatingMode){ 348240616Sjimharris fStartDTDCalled = true; 349240616Sjimharris nvGrammarInfo.startDTD(fEntityScanner,null); 350240616Sjimharris } 351240616Sjimharris // set starting state for internal subset 352240616Sjimharris setScannerState(SCANNER_STATE_MARKUP_DECL); 353240616Sjimharris } 354240616Sjimharris // keep dispatching "events" 355240616Sjimharris do { 356240616Sjimharris if (!scanDecls(complete)) { 357240616Sjimharris // call handler 358240616Sjimharris if (fDTDHandler != null && hasExternalSubset == false) { 359240616Sjimharris fDTDHandler.endDTD(null); 360240616Sjimharris } 361240616Sjimharris if (nonValidatingMode && hasExternalSubset == false ){ 362240616Sjimharris nvGrammarInfo.endDTD(null); 363240616Sjimharris } 364240616Sjimharris // we're done, set starting state for external subset 365240616Sjimharris setScannerState(SCANNER_STATE_TEXT_DECL); 366240616Sjimharris // we're done scanning DTD. 367240616Sjimharris fLimitAnalyzer.reset(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT); 368240616Sjimharris fLimitAnalyzer.reset(XMLSecurityManager.Limit.TOTAL_ENTITY_SIZE_LIMIT); 369240616Sjimharris return false; 370240616Sjimharris } 371240616Sjimharris } while (complete); 372240616Sjimharris 373240616Sjimharris // return that there is more to scan 374240616Sjimharris return true; 375240616Sjimharris 376240616Sjimharris } // scanDTDInternalSubset(boolean,boolean,boolean):boolean 377248773Sjimharris 378248773Sjimharris /** 379248773Sjimharris * Skip the DTD if javax.xml.stream.supportDTD is false. 380240616Sjimharris * 381240616Sjimharris * @param supportDTD The value of the property javax.xml.stream.supportDTD. 382240616Sjimharris * @return true if DTD is skipped, false otherwise. 383240616Sjimharris * @throws java.io.IOException if i/o error occurs 384240616Sjimharris */ 385240616Sjimharris @Override 386240616Sjimharris public boolean skipDTD(boolean supportDTD) throws IOException { 387240616Sjimharris if (supportDTD) 388240616Sjimharris return false; 389240616Sjimharris 390240616Sjimharris fStringBuffer.clear(); 391240616Sjimharris while (fEntityScanner.scanData("]", fStringBuffer, 0)) { 392240616Sjimharris int c = fEntityScanner.peekChar(); 393248757Sjimharris if (c != -1) { 394248757Sjimharris if (XMLChar.isHighSurrogate(c)) { 395248757Sjimharris scanSurrogates(fStringBuffer); 396248757Sjimharris } 397248757Sjimharris if (isInvalidLiteral(c)) { 398240616Sjimharris reportFatalError("InvalidCharInDTD", 399240616Sjimharris new Object[] { Integer.toHexString(c) }); 400240616Sjimharris fEntityScanner.scanChar(null); 401240616Sjimharris } 402240616Sjimharris } 403248758Sjimharris } 404248758Sjimharris fEntityScanner.fCurrentEntity.position--; 405248758Sjimharris return true; 406248758Sjimharris } 407240616Sjimharris 408240616Sjimharris // 409240616Sjimharris // XMLComponent methods 410240616Sjimharris // 411240616Sjimharris 412240616Sjimharris /** 413240616Sjimharris * reset 414240616Sjimharris * 415240616Sjimharris * @param componentManager 416240616Sjimharris */ 417240616Sjimharris public void reset(XMLComponentManager componentManager) 418240616Sjimharris throws XMLConfigurationException { 419240616Sjimharris 420240616Sjimharris super.reset(componentManager); 421240616Sjimharris init(); 422248737Sjimharris 423248737Sjimharris } // reset(XMLComponentManager) 424248737Sjimharris 425248732Sjimharris // this is made for something like XMLDTDLoader--XMLComponentManager-free operation... 426248732Sjimharris public void reset() { 427240616Sjimharris super.reset(); 428248769Sjimharris init(); 429240616Sjimharris 430240616Sjimharris } 431248736Sjimharris 432248746Sjimharris public void reset(PropertyManager props) { 433248746Sjimharris setPropertyManager(props); 434240616Sjimharris super.reset(props); 435248763Sjimharris init() ; 436241660Sjimharris nonValidatingMode = true; 437241660Sjimharris //Revisit : Create new grammar until we implement GrammarPool. 438241660Sjimharris nvGrammarInfo = new DTDGrammar(fSymbolTable); 439241660Sjimharris } 440248767Sjimharris /** 441248767Sjimharris * Returns a list of feature identifiers that are recognized by 442240616Sjimharris * this component. This method may return null if no features 443240616Sjimharris * are recognized by this component. 444240616Sjimharris */ 445252271Sjimharris public String[] getRecognizedFeatures() { 446240616Sjimharris return (String[])(RECOGNIZED_FEATURES.clone()); 447248746Sjimharris } // getRecognizedFeatures():String[] 448248746Sjimharris 449240616Sjimharris /** 450241663Sjimharris * Returns a list of property identifiers that are recognized by 451241663Sjimharris * this component. This method may return null if no properties 452248761Sjimharris * are recognized by this component. 453248767Sjimharris */ 454248767Sjimharris public String[] getRecognizedProperties() { 455248767Sjimharris return (String[])(RECOGNIZED_PROPERTIES.clone()); 456248767Sjimharris } // getRecognizedProperties():String[] 457248767Sjimharris 458240616Sjimharris /** 459248746Sjimharris * Returns the default state for a feature, or null if this 460248746Sjimharris * component does not want to report a default value for this 461240616Sjimharris * feature. 462240616Sjimharris * 463248746Sjimharris * @param featureId The feature identifier. 464248746Sjimharris * 465240616Sjimharris * @since Xerces 2.2.0 466240616Sjimharris */ 467240616Sjimharris public Boolean getFeatureDefault(String featureId) { 468240616Sjimharris for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) { 469248746Sjimharris if (RECOGNIZED_FEATURES[i].equals(featureId)) { 470240616Sjimharris return FEATURE_DEFAULTS[i]; 471240616Sjimharris } 472240616Sjimharris } 473240616Sjimharris return null; 474240616Sjimharris } // getFeatureDefault(String):Boolean 475240616Sjimharris 476240616Sjimharris /** 477240616Sjimharris * Returns the default state for a property, or null if this 478240616Sjimharris * component does not want to report a default value for this 479240616Sjimharris * property. 480240616Sjimharris * 481240616Sjimharris * @param propertyId The property identifier. 482240616Sjimharris * 483240616Sjimharris * @since Xerces 2.2.0 484241659Sjimharris */ 485248771Sjimharris public Object getPropertyDefault(String propertyId) { 486241659Sjimharris for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) { 487241659Sjimharris if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) { 488241659Sjimharris return PROPERTY_DEFAULTS[i]; 489241659Sjimharris } 490248771Sjimharris } 491248771Sjimharris return null; 492248771Sjimharris } // getPropertyDefault(String):Object 493248771Sjimharris 494248771Sjimharris // 495248771Sjimharris // XMLDTDSource methods 496248771Sjimharris // 497241659Sjimharris 498248771Sjimharris /** 499248913Sjimharris * setDTDHandler 500248913Sjimharris * 501248771Sjimharris * @param dtdHandler 502248771Sjimharris */ 503241659Sjimharris public void setDTDHandler(XMLDTDHandler dtdHandler) { 504248771Sjimharris fDTDHandler = dtdHandler; 505248771Sjimharris } // setDTDHandler(XMLDTDHandler) 506248913Sjimharris 507248913Sjimharris /** 508248771Sjimharris * getDTDHandler 509248771Sjimharris * 510241659Sjimharris * @return the XMLDTDHandler 511241659Sjimharris */ 512241659Sjimharris public XMLDTDHandler getDTDHandler() { 513241661Sjimharris return fDTDHandler; 514248913Sjimharris } // getDTDHandler(): XMLDTDHandler 515241661Sjimharris 516241661Sjimharris // 517241661Sjimharris // XMLDTDContentModelSource methods 518248771Sjimharris // 519248771Sjimharris 520248913Sjimharris /** 521241661Sjimharris * setDTDContentModelHandler 522241661Sjimharris * 523241661Sjimharris * @param dtdContentModelHandler 524248913Sjimharris */ 525248977Sjimharris public void setDTDContentModelHandler(XMLDTDContentModelHandler 526248977Sjimharris dtdContentModelHandler) { 527248977Sjimharris fDTDContentModelHandler = dtdContentModelHandler; 528248977Sjimharris } // setDTDContentModelHandler 529248977Sjimharris 530248977Sjimharris /** 531248977Sjimharris * getDTDContentModelHandler 532248977Sjimharris * 533248977Sjimharris * @return XMLDTDContentModelHandler 534248977Sjimharris */ 535248977Sjimharris public XMLDTDContentModelHandler getDTDContentModelHandler() { 536248977Sjimharris return fDTDContentModelHandler ; 537248977Sjimharris } // setDTDContentModelHandler 538248977Sjimharris 539248977Sjimharris // 540248977Sjimharris // XMLEntityHandler methods 541248977Sjimharris // 542248977Sjimharris 543241659Sjimharris /** 544241659Sjimharris * This method notifies of the start of an entity. The DTD has the 545248738Sjimharris * pseudo-name of "[dtd]" parameter entity names start with '%'; and 546248760Sjimharris * general entities are just specified by their name. 547248760Sjimharris * 548248760Sjimharris * @param name The name of the entity. 549248767Sjimharris * @param identifier The resource identifier. 550248738Sjimharris * @param encoding The auto-detected IANA encoding name of the entity 551240616Sjimharris * stream. This value will be null in those situations 552 * where the entity encoding is not auto-detected (e.g. 553 * internal entities or a document entity that is 554 * parsed from a java.io.Reader). 555 * @param augs Additional information that may include infoset augmentations 556 * 557 * @throws XNIException Thrown by handler to signal an error. 558 */ 559 public void startEntity(String name, 560 XMLResourceIdentifier identifier, 561 String encoding, Augmentations augs) throws XNIException { 562 563 super.startEntity(name, identifier, encoding, augs); 564 565 boolean dtdEntity = name.equals("[dtd]"); 566 if (dtdEntity) { 567 // call handler 568 if (fDTDHandler != null && !fStartDTDCalled ) { 569 fDTDHandler.startDTD(fEntityScanner, null); 570 } 571 if (fDTDHandler != null) { 572 fDTDHandler.startExternalSubset(identifier,null); 573 } 574 fEntityManager.startExternalSubset(); 575 fEntityStore.startExternalSubset(); 576 fExtEntityDepth++; 577 } 578 else if (name.charAt(0) == '%') { 579 pushPEStack(fMarkUpDepth, fReportEntity); 580 if (fEntityScanner.isExternal()) { 581 fExtEntityDepth++; 582 } 583 } 584 585 // call handler 586 if (fDTDHandler != null && !dtdEntity && fReportEntity) { 587 fDTDHandler.startParameterEntity(name, identifier, encoding, null); 588 } 589 590 } // startEntity(String,XMLResourceIdentifier,String) 591 592 /** 593 * This method notifies the end of an entity. The DTD has the pseudo-name 594 * of "[dtd]" parameter entity names start with '%'; and general entities 595 * are just specified by their name. 596 * 597 * @param name The name of the entity. 598 * 599 * @throws XNIException Thrown by handler to signal an error. 600 */ 601 public void endEntity(String name, Augmentations augs) 602 throws XNIException, IOException { 603 604 super.endEntity(name, augs); 605 606 // if there is no data after the doctype 607 // 608 if (fScannerState == SCANNER_STATE_END_OF_INPUT) 609 return; 610 611 // Handle end of PE 612 boolean reportEntity = fReportEntity; 613 if (name.startsWith("%")) { 614 reportEntity = peekReportEntity(); 615 // check well-formedness of the entity 616 int startMarkUpDepth = popPEStack(); 617 // throw fatalError if this entity was incomplete and 618 // was a freestanding decl 619 if(startMarkUpDepth == 0 && 620 startMarkUpDepth < fMarkUpDepth) { 621 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 622 "ILL_FORMED_PARAMETER_ENTITY_WHEN_USED_IN_DECL", 623 new Object[]{ fEntityManager.fCurrentEntity.name}, 624 XMLErrorReporter.SEVERITY_FATAL_ERROR); 625 } 626 if (startMarkUpDepth != fMarkUpDepth) { 627 reportEntity = false; 628 if (fValidation) { 629 // Proper nesting of parameter entities is a Validity Constraint 630 // and must not be enforced when validation is off 631 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 632 "ImproperDeclarationNesting", 633 new Object[]{ name }, 634 XMLErrorReporter.SEVERITY_ERROR); 635 } 636 } 637 if (fEntityScanner.isExternal()) { 638 fExtEntityDepth--; 639 } 640 } 641 642 // call handler 643 boolean dtdEntity = name.equals("[dtd]"); 644 if (fDTDHandler != null && !dtdEntity && reportEntity) { 645 fDTDHandler.endParameterEntity(name, null); 646 } 647 648 // end DTD 649 if (dtdEntity) { 650 if (fIncludeSectDepth != 0) { 651 reportFatalError("IncludeSectUnterminated", null); 652 } 653 fScannerState = SCANNER_STATE_END_OF_INPUT; 654 // call handler 655 fEntityManager.endExternalSubset(); 656 fEntityStore.endExternalSubset(); 657 658 if (fDTDHandler != null) { 659 fDTDHandler.endExternalSubset(null); 660 fDTDHandler.endDTD(null); 661 } 662 fExtEntityDepth--; 663 } 664 665 //XML (Document Entity) is the last opened entity, however 666 //if for some reason DTD Scanner receives this callback 667 //there is something wrong (probably invalid XML), throw exception. 668 //or 669 //For standalone DTD loader, it might be the last opened entity 670 //and if this is the last opened entity and fMarkUpDepth != 0 or 671 //fIncludeSectDepth != 0 or fExtEntityDepth != 0 throw Exception 672 if (augs != null && Boolean.TRUE.equals(augs.getItem(Constants.LAST_ENTITY)) 673 && ( fMarkUpDepth != 0 || fExtEntityDepth !=0 || fIncludeSectDepth != 0)){ 674 throw new EOFException(); 675 } 676 677 } // endEntity(String) 678 679 // helper methods 680 681 /** 682 * Sets the scanner state. 683 * 684 * @param state The new scanner state. 685 */ 686 protected final void setScannerState(int state) { 687 688 fScannerState = state; 689 if (DEBUG_SCANNER_STATE) { 690 System.out.print("### setScannerState: "); 691 System.out.print(getScannerStateName(state)); 692 //System.out.println(); 693 } 694 695 } // setScannerState(int) 696 697 // 698 // Private methods 699 // 700 701 /** Returns the scanner state name. */ 702 private static String getScannerStateName(int state) { 703 704 if (DEBUG_SCANNER_STATE) { 705 switch (state) { 706 case SCANNER_STATE_END_OF_INPUT: return "SCANNER_STATE_END_OF_INPUT"; 707 case SCANNER_STATE_TEXT_DECL: return "SCANNER_STATE_TEXT_DECL"; 708 case SCANNER_STATE_MARKUP_DECL: return "SCANNER_STATE_MARKUP_DECL"; 709 } 710 } 711 712 return "??? ("+state+')'; 713 714 } // getScannerStateName(int):String 715 716 protected final boolean scanningInternalSubset() { 717 return fExtEntityDepth == 0; 718 } 719 720 /** 721 * start a parameter entity dealing with the textdecl if there is any 722 * 723 * @param name The name of the parameter entity to start (without the '%') 724 * @param literal Whether this is happening within a literal 725 */ 726 protected void startPE(String name, boolean literal) 727 throws IOException, XNIException { 728 int depth = fPEDepth; 729 String pName = "%"+name; 730 if (fValidation && !fEntityStore.isDeclaredEntity(pName)) { 731 fErrorReporter.reportError( XMLMessageFormatter.XML_DOMAIN,"EntityNotDeclared", 732 new Object[]{name}, XMLErrorReporter.SEVERITY_ERROR); 733 } 734 fEntityManager.startEntity(false, fSymbolTable.addSymbol(pName), 735 literal); 736 // if we actually got a new entity and it's external 737 // parse text decl if there is any 738 if (depth != fPEDepth && fEntityScanner.isExternal()) { 739 scanTextDecl(); 740 } 741 } 742 743 /** 744 * Dispatch an XML "event". 745 * 746 * @param complete True if this method is intended to scan 747 * and dispatch as much as possible. 748 * 749 * @return True if a TextDecl was scanned. 750 * 751 * @throws IOException Thrown on i/o error. 752 * @throws XNIException Thrown on parse error. 753 * 754 */ 755 protected final boolean scanTextDecl() 756 throws IOException, XNIException { 757 758 // scan XMLDecl 759 boolean textDecl = false; 760 if (fEntityScanner.skipString("<?xml")) { 761 fMarkUpDepth++; 762 // NOTE: special case where document starts with a PI 763 // whose name starts with "xml" (e.g. "xmlfoo") 764 if (isValidNameChar(fEntityScanner.peekChar())) { 765 fStringBuffer.clear(); 766 fStringBuffer.append("xml"); 767 while (isValidNameChar(fEntityScanner.peekChar())) { 768 fStringBuffer.append((char)fEntityScanner.scanChar(null)); 769 } 770 String target = 771 fSymbolTable.addSymbol(fStringBuffer.ch, 772 fStringBuffer.offset, 773 fStringBuffer.length); 774 scanPIData(target, fString); 775 } 776 777 // standard Text declaration 778 else { 779 // pseudo-attribute values 780 String version = null; 781 String encoding = null; 782 783 scanXMLDeclOrTextDecl(true, fStrings); 784 textDecl = true; 785 fMarkUpDepth--; 786 787 version = fStrings[0]; 788 encoding = fStrings[1]; 789 790 fEntityScanner.setEncoding(encoding); 791 792 // call handler 793 if (fDTDHandler != null) { 794 fDTDHandler.textDecl(version, encoding, null); 795 } 796 } 797 } 798 fEntityManager.fCurrentEntity.mayReadChunks = true; 799 800 return textDecl; 801 802 } // scanTextDecl(boolean):boolean 803 804 /** 805 * Scans a processing data. This is needed to handle the situation 806 * where a document starts with a processing instruction whose 807 * target name <em>starts with</em> "xml". (e.g. xmlfoo) 808 * 809 * @param target The PI target 810 * @param data The string to fill in with the data 811 */ 812 protected final void scanPIData(String target, XMLString data) 813 throws IOException, XNIException { 814 //Venu REVISIT 815 // super.scanPIData(target, data); 816 fMarkUpDepth--; 817 818 // call handler 819 if (fDTDHandler != null) { 820 fDTDHandler.processingInstruction(target, data, null); 821 } 822 823 } // scanPIData(String) 824 825 /** 826 * Scans a comment. 827 * <p> 828 * <pre> 829 * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->' 830 * </pre> 831 * <p> 832 * <strong>Note:</strong> Called after scanning past '<!--' 833 */ 834 protected final void scanComment() throws IOException, XNIException { 835 836 fReportEntity = false; 837 scanComment(fStringBuffer); 838 fMarkUpDepth--; 839 840 // call handler 841 if (fDTDHandler != null) { 842 fDTDHandler.comment(fStringBuffer, null); 843 } 844 fReportEntity = true; 845 846 } // scanComment() 847 848 /** 849 * Scans an element declaration 850 * <p> 851 * <pre> 852 * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>' 853 * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children 854 * </pre> 855 * <p> 856 * <strong>Note:</strong> Called after scanning past '<!ELEMENT' 857 */ 858 protected final void scanElementDecl() throws IOException, XNIException { 859 860 // spaces 861 fReportEntity = false; 862 if (!skipSeparator(true, !scanningInternalSubset())) { 863 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL", 864 null); 865 } 866 867 // element name 868 String name = fEntityScanner.scanName(NameType.ELEMENTSTART); 869 if (name == null) { 870 reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL", 871 null); 872 } 873 874 // spaces 875 if (!skipSeparator(true, !scanningInternalSubset())) { 876 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_CONTENTSPEC_IN_ELEMENTDECL", 877 new Object[]{name}); 878 } 879 880 // content model 881 if (fDTDContentModelHandler != null) { 882 fDTDContentModelHandler.startContentModel(name, null); 883 } 884 String contentModel = null; 885 fReportEntity = true; 886 if (fEntityScanner.skipString("EMPTY")) { 887 contentModel = "EMPTY"; 888 // call handler 889 if (fDTDContentModelHandler != null) { 890 fDTDContentModelHandler.empty(null); 891 } 892 } 893 else if (fEntityScanner.skipString("ANY")) { 894 contentModel = "ANY"; 895 // call handler 896 if (fDTDContentModelHandler != null) { 897 fDTDContentModelHandler.any(null); 898 } 899 } 900 else { 901 if (!fEntityScanner.skipChar('(', null)) { 902 reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN", 903 new Object[]{name}); 904 } 905 if (fDTDContentModelHandler != null) { 906 fDTDContentModelHandler.startGroup(null); 907 } 908 fStringBuffer.clear(); 909 fStringBuffer.append('('); 910 fMarkUpDepth++; 911 skipSeparator(false, !scanningInternalSubset()); 912 913 // Mixed content model 914 if (fEntityScanner.skipString("#PCDATA")) { 915 scanMixed(name); 916 } 917 else { // children content 918 scanChildren(name); 919 } 920 contentModel = fStringBuffer.toString(); 921 } 922 923 // call handler 924 if (fDTDContentModelHandler != null) { 925 fDTDContentModelHandler.endContentModel(null); 926 } 927 928 fReportEntity = false; 929 skipSeparator(false, !scanningInternalSubset()); 930 // end 931 if (!fEntityScanner.skipChar('>', null)) { 932 reportFatalError("ElementDeclUnterminated", new Object[]{name}); 933 } 934 fReportEntity = true; 935 fMarkUpDepth--; 936 937 // call handler 938 if (fDTDHandler != null) { 939 fDTDHandler.elementDecl(name, contentModel, null); 940 } 941 if (nonValidatingMode) nvGrammarInfo.elementDecl(name, contentModel, null); 942 } // scanElementDecl() 943 944 /** 945 * scan Mixed content model 946 * This assumes the content model has been parsed up to #PCDATA and 947 * can simply append to fStringBuffer. 948 * <pre> 949 * [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' 950 * | '(' S? '#PCDATA' S? ')' 951 * </pre> 952 * 953 * @param elName The element type name this declaration is about. 954 * 955 * <strong>Note:</strong> Called after scanning past '(#PCDATA'. 956 */ 957 private final void scanMixed(String elName) 958 throws IOException, XNIException { 959 960 String childName = null; 961 962 fStringBuffer.append("#PCDATA"); 963 // call handler 964 if (fDTDContentModelHandler != null) { 965 fDTDContentModelHandler.pcdata(null); 966 } 967 skipSeparator(false, !scanningInternalSubset()); 968 while (fEntityScanner.skipChar('|', null)) { 969 fStringBuffer.append('|'); 970 // call handler 971 if (fDTDContentModelHandler != null) { 972 fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_CHOICE, 973 null); 974 } 975 skipSeparator(false, !scanningInternalSubset()); 976 977 childName = fEntityScanner.scanName(NameType.ENTITY); 978 if (childName == null) { 979 reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_MIXED_CONTENT", 980 new Object[]{elName}); 981 } 982 fStringBuffer.append(childName); 983 // call handler 984 if (fDTDContentModelHandler != null) { 985 fDTDContentModelHandler.element(childName, null); 986 } 987 skipSeparator(false, !scanningInternalSubset()); 988 } 989 // The following check must be done in a single call (as opposed to one 990 // for ')' and then one for '*') to guarantee that callbacks are 991 // properly nested. We do not want to trigger endEntity too early in 992 // case we cross the boundary of an entity between the two characters. 993 if (fEntityScanner.skipString(")*")) { 994 fStringBuffer.append(")*"); 995 // call handler 996 if (fDTDContentModelHandler != null) { 997 fDTDContentModelHandler.endGroup(null); 998 fDTDContentModelHandler.occurrence(XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE, 999 null); 1000 } 1001 } 1002 else if (childName != null) { 1003 reportFatalError("MixedContentUnterminated", 1004 new Object[]{elName}); 1005 } 1006 else if (fEntityScanner.skipChar(')', null)){ 1007 fStringBuffer.append(')'); 1008 // call handler 1009 if (fDTDContentModelHandler != null) { 1010 fDTDContentModelHandler.endGroup(null); 1011 } 1012 } 1013 else { 1014 reportFatalError("MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN", 1015 new Object[]{elName}); 1016 } 1017 fMarkUpDepth--; 1018 // we are done 1019 } 1020 1021 /** 1022 * scan children content model 1023 * This assumes it can simply append to fStringBuffer. 1024 * <pre> 1025 * [47] children ::= (choice | seq) ('?' | '*' | '+')? 1026 * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')? 1027 * [49] choice ::= '(' S? cp ( S? '|' S? cp )+ S? ')' 1028 * [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')' 1029 * </pre> 1030 * 1031 * @param elName The element type name this declaration is about. 1032 * 1033 * <strong>Note:</strong> Called after scanning past the first open 1034 * paranthesis. 1035 */ 1036 private final void scanChildren(String elName) 1037 throws IOException, XNIException { 1038 1039 fContentDepth = 0; 1040 pushContentStack(0); 1041 int currentOp = 0; 1042 int c; 1043 while (true) { 1044 if (fEntityScanner.skipChar('(', null)) { 1045 fMarkUpDepth++; 1046 fStringBuffer.append('('); 1047 // call handler 1048 if (fDTDContentModelHandler != null) { 1049 fDTDContentModelHandler.startGroup(null); 1050 } 1051 // push current op on stack and reset it 1052 pushContentStack(currentOp); 1053 currentOp = 0; 1054 skipSeparator(false, !scanningInternalSubset()); 1055 continue; 1056 } 1057 skipSeparator(false, !scanningInternalSubset()); 1058 String childName = fEntityScanner.scanName(NameType.ELEMENTSTART); 1059 if (childName == null) { 1060 reportFatalError("MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN", 1061 new Object[]{elName}); 1062 return; 1063 } 1064 // call handler 1065 if (fDTDContentModelHandler != null) { 1066 fDTDContentModelHandler.element(childName, null); 1067 } 1068 fStringBuffer.append(childName); 1069 c = fEntityScanner.peekChar(); 1070 if (c == '?' || c == '*' || c == '+') { 1071 // call handler 1072 if (fDTDContentModelHandler != null) { 1073 short oc; 1074 if (c == '?') { 1075 oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE; 1076 } 1077 else if (c == '*') { 1078 oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE; 1079 } 1080 else { 1081 oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE; 1082 } 1083 fDTDContentModelHandler.occurrence(oc, null); 1084 } 1085 fEntityScanner.scanChar(null); 1086 fStringBuffer.append((char)c); 1087 } 1088 while (true) { 1089 skipSeparator(false, !scanningInternalSubset()); 1090 c = fEntityScanner.peekChar(); 1091 if (c == ',' && currentOp != '|') { 1092 currentOp = c; 1093 // call handler 1094 if (fDTDContentModelHandler != null) { 1095 fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_SEQUENCE, 1096 null); 1097 } 1098 fEntityScanner.scanChar(null); 1099 fStringBuffer.append(','); 1100 break; 1101 } 1102 else if (c == '|' && currentOp != ',') { 1103 currentOp = c; 1104 // call handler 1105 if (fDTDContentModelHandler != null) { 1106 fDTDContentModelHandler.separator(XMLDTDContentModelHandler.SEPARATOR_CHOICE, 1107 null); 1108 } 1109 fEntityScanner.scanChar(null); 1110 fStringBuffer.append('|'); 1111 break; 1112 } 1113 else if (c != ')') { 1114 reportFatalError("MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN", 1115 new Object[]{elName}); 1116 } 1117 // call handler 1118 if (fDTDContentModelHandler != null) { 1119 fDTDContentModelHandler.endGroup(null); 1120 } 1121 // restore previous op 1122 currentOp = popContentStack(); 1123 short oc; 1124 // The following checks must be done in a single call (as 1125 // opposed to one for ')' and then one for '?', '*', and '+') 1126 // to guarantee that callbacks are properly nested. We do not 1127 // want to trigger endEntity too early in case we cross the 1128 // boundary of an entity between the two characters. 1129 if (fEntityScanner.skipString(")?")) { 1130 fStringBuffer.append(")?"); 1131 // call handler 1132 if (fDTDContentModelHandler != null) { 1133 oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE; 1134 fDTDContentModelHandler.occurrence(oc, null); 1135 } 1136 } 1137 else if (fEntityScanner.skipString(")+")) { 1138 fStringBuffer.append(")+"); 1139 // call handler 1140 if (fDTDContentModelHandler != null) { 1141 oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE; 1142 fDTDContentModelHandler.occurrence(oc, null); 1143 } 1144 } 1145 else if (fEntityScanner.skipString(")*")) { 1146 fStringBuffer.append(")*"); 1147 // call handler 1148 if (fDTDContentModelHandler != null) { 1149 oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE; 1150 fDTDContentModelHandler.occurrence(oc, null); 1151 } 1152 } 1153 else { 1154 // no occurrence specified 1155 fEntityScanner.scanChar(null); 1156 fStringBuffer.append(')'); 1157 } 1158 fMarkUpDepth--; 1159 if (fContentDepth == 0) { 1160 return; 1161 } 1162 } 1163 skipSeparator(false, !scanningInternalSubset()); 1164 } 1165 } 1166 1167 /** 1168 * Scans an attlist declaration 1169 * <p> 1170 * <pre> 1171 * [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>' 1172 * [53] AttDef ::= S Name S AttType S DefaultDecl 1173 * </pre> 1174 * <p> 1175 * <strong>Note:</strong> Called after scanning past '<!ATTLIST' 1176 */ 1177 protected final void scanAttlistDecl() throws IOException, XNIException { 1178 1179 // spaces 1180 fReportEntity = false; 1181 if (!skipSeparator(true, !scanningInternalSubset())) { 1182 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ATTLISTDECL", 1183 null); 1184 } 1185 1186 // element name 1187 String elName = fEntityScanner.scanName(NameType.ELEMENTSTART); 1188 if (elName == null) { 1189 reportFatalError("MSG_ELEMENT_TYPE_REQUIRED_IN_ATTLISTDECL", 1190 null); 1191 } 1192 1193 // call handler 1194 if (fDTDHandler != null) { 1195 fDTDHandler.startAttlist(elName, null); 1196 } 1197 1198 // spaces 1199 if (!skipSeparator(true, !scanningInternalSubset())) { 1200 // no space, is it the end yet? 1201 if (fEntityScanner.skipChar('>', null)) { 1202 // yes, stop here 1203 // call handler 1204 if (fDTDHandler != null) { 1205 fDTDHandler.endAttlist(null); 1206 } 1207 fMarkUpDepth--; 1208 return; 1209 } 1210 else { 1211 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ATTRIBUTE_NAME_IN_ATTDEF", 1212 new Object[]{elName}); 1213 } 1214 } 1215 1216 // definitions 1217 while (!fEntityScanner.skipChar('>', null)) { 1218 String name = fEntityScanner.scanName(NameType.ATTRIBUTE); 1219 if (name == null) { 1220 reportFatalError("AttNameRequiredInAttDef", 1221 new Object[]{elName}); 1222 } 1223 // spaces 1224 if (!skipSeparator(true, !scanningInternalSubset())) { 1225 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ATTTYPE_IN_ATTDEF", 1226 new Object[]{elName, name}); 1227 } 1228 // type 1229 String type = scanAttType(elName, name); 1230 1231 // spaces 1232 if (!skipSeparator(true, !scanningInternalSubset())) { 1233 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_DEFAULTDECL_IN_ATTDEF", 1234 new Object[]{elName, name}); 1235 } 1236 1237 // default decl 1238 String defaultType = scanAttDefaultDecl(elName, name, 1239 type, 1240 fLiteral, fLiteral2); 1241 // REVISIT: Should we do anything with the non-normalized 1242 // default attribute value? -Ac 1243 // yes--according to bug 5073. - neilg 1244 String[] enumr = null; 1245 if( fDTDHandler != null || nonValidatingMode){ 1246 if (fEnumerationCount != 0) { 1247 enumr = new String[fEnumerationCount]; 1248 System.arraycopy(fEnumeration, 0, enumr, 1249 0, fEnumerationCount); 1250 } 1251 } 1252 // call handler 1253 // Determine whether the default value to be passed should be null. 1254 // REVISIT: should probably check whether fLiteral.ch is null instead. LM. 1255 if (defaultType!=null && (defaultType.equals("#REQUIRED") || 1256 defaultType.equals("#IMPLIED"))) { 1257 if (fDTDHandler != null){ 1258 fDTDHandler.attributeDecl(elName, name, type, enumr, 1259 defaultType, null, null, null); 1260 } 1261 if(nonValidatingMode){ 1262 nvGrammarInfo.attributeDecl(elName, name, type, enumr, 1263 defaultType, null, null, null); 1264 1265 } 1266 } 1267 else { 1268 if (fDTDHandler != null){ 1269 fDTDHandler.attributeDecl(elName, name, type, enumr, 1270 defaultType, fLiteral, fLiteral2, null); 1271 } 1272 if(nonValidatingMode){ 1273 nvGrammarInfo.attributeDecl(elName, name, type, enumr, 1274 defaultType, fLiteral, fLiteral2, null); 1275 } 1276 } 1277 skipSeparator(false, !scanningInternalSubset()); 1278 } 1279 1280 // call handler 1281 if (fDTDHandler != null) { 1282 fDTDHandler.endAttlist(null); 1283 } 1284 fMarkUpDepth--; 1285 fReportEntity = true; 1286 1287 } // scanAttlistDecl() 1288 1289 /** 1290 * Scans an attribute type definition 1291 * <p> 1292 * <pre> 1293 * [54] AttType ::= StringType | TokenizedType | EnumeratedType 1294 * [55] StringType ::= 'CDATA' 1295 * [56] TokenizedType ::= 'ID' 1296 * | 'IDREF' 1297 * | 'IDREFS' 1298 * | 'ENTITY' 1299 * | 'ENTITIES' 1300 * | 'NMTOKEN' 1301 * | 'NMTOKENS' 1302 * [57] EnumeratedType ::= NotationType | Enumeration 1303 * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')' 1304 * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')' 1305 * </pre> 1306 * <p> 1307 * <strong>Note:</strong> Called after scanning past '<!ATTLIST' 1308 * 1309 * @param elName The element type name this declaration is about. 1310 * @param atName The attribute name this declaration is about. 1311 */ 1312 private final String scanAttType(String elName, String atName) 1313 throws IOException, XNIException { 1314 1315 String type = null; 1316 fEnumerationCount = 0; 1317 /* 1318 * Watchout: the order here is important: when a string happens to 1319 * be a substring of another string, the longer one needs to be 1320 * looked for first!! 1321 */ 1322 if (fEntityScanner.skipString("CDATA")) { 1323 type = "CDATA"; 1324 } 1325 else if (fEntityScanner.skipString("IDREFS")) { 1326 type = "IDREFS"; 1327 } 1328 else if (fEntityScanner.skipString("IDREF")) { 1329 type = "IDREF"; 1330 } 1331 else if (fEntityScanner.skipString("ID")) { 1332 type = "ID"; 1333 } 1334 else if (fEntityScanner.skipString("ENTITY")) { 1335 type = "ENTITY"; 1336 } 1337 else if (fEntityScanner.skipString("ENTITIES")) { 1338 type = "ENTITIES"; 1339 } 1340 else if (fEntityScanner.skipString("NMTOKENS")) { 1341 type = "NMTOKENS"; 1342 } 1343 else if (fEntityScanner.skipString("NMTOKEN")) { 1344 type = "NMTOKEN"; 1345 } 1346 else if (fEntityScanner.skipString("NOTATION")) { 1347 type = "NOTATION"; 1348 // spaces 1349 if (!skipSeparator(true, !scanningInternalSubset())) { 1350 reportFatalError("MSG_SPACE_REQUIRED_AFTER_NOTATION_IN_NOTATIONTYPE", 1351 new Object[]{elName, atName}); 1352 } 1353 // open paren 1354 int c = fEntityScanner.scanChar(null); 1355 if (c != '(') { 1356 reportFatalError("MSG_OPEN_PAREN_REQUIRED_IN_NOTATIONTYPE", 1357 new Object[]{elName, atName}); 1358 } 1359 fMarkUpDepth++; 1360 do { 1361 skipSeparator(false, !scanningInternalSubset()); 1362 String aName = fEntityScanner.scanName(NameType.ATTRIBUTE); 1363 if (aName == null) { 1364 reportFatalError("MSG_NAME_REQUIRED_IN_NOTATIONTYPE", 1365 new Object[]{elName, atName}); 1366 } 1367 ensureEnumerationSize(fEnumerationCount + 1); 1368 fEnumeration[fEnumerationCount++] = aName; 1369 skipSeparator(false, !scanningInternalSubset()); 1370 c = fEntityScanner.scanChar(null); 1371 } while (c == '|'); 1372 if (c != ')') { 1373 reportFatalError("NotationTypeUnterminated", 1374 new Object[]{elName, atName}); 1375 } 1376 fMarkUpDepth--; 1377 } 1378 else { // Enumeration 1379 type = "ENUMERATION"; 1380 // open paren 1381 int c = fEntityScanner.scanChar(null); 1382 if (c != '(') { 1383 // "OPEN_PAREN_REQUIRED_BEFORE_ENUMERATION_IN_ATTRDECL", 1384 reportFatalError("AttTypeRequiredInAttDef", 1385 new Object[]{elName, atName}); 1386 } 1387 fMarkUpDepth++; 1388 do { 1389 skipSeparator(false, !scanningInternalSubset()); 1390 String token = fEntityScanner.scanNmtoken(); 1391 if (token == null) { 1392 reportFatalError("MSG_NMTOKEN_REQUIRED_IN_ENUMERATION", 1393 new Object[]{elName, atName}); 1394 } 1395 ensureEnumerationSize(fEnumerationCount + 1); 1396 fEnumeration[fEnumerationCount++] = token; 1397 skipSeparator(false, !scanningInternalSubset()); 1398 c = fEntityScanner.scanChar(null); 1399 } while (c == '|'); 1400 if (c != ')') { 1401 reportFatalError("EnumerationUnterminated", 1402 new Object[]{elName, atName}); 1403 } 1404 fMarkUpDepth--; 1405 } 1406 return type; 1407 1408 } // scanAttType():String 1409 1410 1411 /** 1412 * Scans an attribute default declaration 1413 * <p> 1414 * <pre> 1415 * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue) 1416 * </pre> 1417 * 1418 * @param name The name of the attribute being scanned. 1419 * @param defaultVal The string to fill in with the default value. 1420 */ 1421 protected final String scanAttDefaultDecl(String elName, String atName, 1422 String type, 1423 XMLString defaultVal, 1424 XMLString nonNormalizedDefaultVal) 1425 throws IOException, XNIException { 1426 1427 String defaultType = null; 1428 fString.clear(); 1429 defaultVal.clear(); 1430 if (fEntityScanner.skipString("#REQUIRED")) { 1431 defaultType = "#REQUIRED"; 1432 } 1433 else if (fEntityScanner.skipString("#IMPLIED")) { 1434 defaultType = "#IMPLIED"; 1435 } 1436 else { 1437 if (fEntityScanner.skipString("#FIXED")) { 1438 defaultType = "#FIXED"; 1439 // spaces 1440 if (!skipSeparator(true, !scanningInternalSubset())) { 1441 reportFatalError("MSG_SPACE_REQUIRED_AFTER_FIXED_IN_DEFAULTDECL", 1442 new Object[]{elName, atName}); 1443 } 1444 } 1445 // AttValue 1446 boolean isVC = !fStandalone && (fSeenExternalDTD || fSeenExternalPE) ; 1447 scanAttributeValue(defaultVal, nonNormalizedDefaultVal, atName, 1448 fAttributes, 0, isVC, elName, false); 1449 } 1450 return defaultType; 1451 1452 } // ScanAttDefaultDecl 1453 1454 /** 1455 * Scans an entity declaration 1456 * <p> 1457 * <pre> 1458 * [70] EntityDecl ::= GEDecl | PEDecl 1459 * [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>' 1460 * [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>' 1461 * [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?) 1462 * [74] PEDef ::= EntityValue | ExternalID 1463 * [75] ExternalID ::= 'SYSTEM' S SystemLiteral 1464 * | 'PUBLIC' S PubidLiteral S SystemLiteral 1465 * [76] NDataDecl ::= S 'NDATA' S Name 1466 * </pre> 1467 * <p> 1468 * <strong>Note:</strong> Called after scanning past '<!ENTITY' 1469 */ 1470 private final void scanEntityDecl() throws IOException, XNIException { 1471 1472 boolean isPEDecl = false; 1473 boolean sawPERef = false; 1474 fReportEntity = false; 1475 if (fEntityScanner.skipSpaces()) { 1476 if (!fEntityScanner.skipChar('%', NameType.REFERENCE)) { 1477 isPEDecl = false; // <!ENTITY x "x"> 1478 } 1479 else if (skipSeparator(true, !scanningInternalSubset())) { 1480 // <!ENTITY % x "x"> 1481 isPEDecl = true; 1482 } 1483 else if (scanningInternalSubset()) { 1484 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL", 1485 null); 1486 isPEDecl = true; 1487 } 1488 else if (fEntityScanner.peekChar() == '%') { 1489 // <!ENTITY %%x; "x"> is legal 1490 skipSeparator(false, !scanningInternalSubset()); 1491 isPEDecl = true; 1492 } 1493 else { 1494 sawPERef = true; 1495 } 1496 } 1497 else if (scanningInternalSubset() || !fEntityScanner.skipChar('%', NameType.REFERENCE)) { 1498 // <!ENTITY[^ ]...> or <!ENTITY[^ %]...> 1499 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL", 1500 null); 1501 isPEDecl = false; 1502 } 1503 else if (fEntityScanner.skipSpaces()) { 1504 // <!ENTITY% ...> 1505 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_PERCENT_IN_PEDECL", 1506 null); 1507 isPEDecl = false; 1508 } 1509 else { 1510 sawPERef = true; 1511 } 1512 if (sawPERef) { 1513 while (true) { 1514 String peName = fEntityScanner.scanName(NameType.REFERENCE); 1515 if (peName == null) { 1516 reportFatalError("NameRequiredInPEReference", null); 1517 } 1518 else if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) { 1519 reportFatalError("SemicolonRequiredInPEReference", 1520 new Object[]{peName}); 1521 } 1522 else { 1523 startPE(peName, false); 1524 } 1525 fEntityScanner.skipSpaces(); 1526 if (!fEntityScanner.skipChar('%', NameType.REFERENCE)) 1527 break; 1528 if (!isPEDecl) { 1529 if (skipSeparator(true, !scanningInternalSubset())) { 1530 isPEDecl = true; 1531 break; 1532 } 1533 isPEDecl = fEntityScanner.skipChar('%', NameType.REFERENCE); 1534 } 1535 } 1536 } 1537 1538 // name 1539 String name = fEntityScanner.scanName(NameType.ENTITY); 1540 if (name == null) { 1541 reportFatalError("MSG_ENTITY_NAME_REQUIRED_IN_ENTITYDECL", null); 1542 } 1543 1544 // spaces 1545 if (!skipSeparator(true, !scanningInternalSubset())) { 1546 reportFatalError("MSG_SPACE_REQUIRED_AFTER_ENTITY_NAME_IN_ENTITYDECL", 1547 new Object[]{name}); 1548 } 1549 1550 // external id 1551 scanExternalID(fStrings, false); 1552 String systemId = fStrings[0]; 1553 String publicId = fStrings[1]; 1554 1555 if (isPEDecl && systemId != null) { 1556 fSeenExternalPE = true; 1557 } 1558 1559 String notation = null; 1560 // NDATA 1561 boolean sawSpace = skipSeparator(true, !scanningInternalSubset()); 1562 if (!isPEDecl && fEntityScanner.skipString("NDATA")) { 1563 // check whether there was space before NDATA 1564 if (!sawSpace) { 1565 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NDATA_IN_UNPARSED_ENTITYDECL", 1566 new Object[]{name}); 1567 } 1568 1569 // spaces 1570 if (!skipSeparator(true, !scanningInternalSubset())) { 1571 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_UNPARSED_ENTITYDECL", 1572 new Object[]{name}); 1573 } 1574 notation = fEntityScanner.scanName(NameType.NOTATION); 1575 if (notation == null) { 1576 reportFatalError("MSG_NOTATION_NAME_REQUIRED_FOR_UNPARSED_ENTITYDECL", 1577 new Object[]{name}); 1578 } 1579 } 1580 1581 // internal entity 1582 if (systemId == null) { 1583 scanEntityValue(name, isPEDecl, fLiteral, fLiteral2); 1584 // since we need it's value anyway, let's snag it so it doesn't get corrupted 1585 // if a new load takes place before we store the entity values 1586 fStringBuffer.clear(); 1587 fStringBuffer2.clear(); 1588 fStringBuffer.append(fLiteral.ch, fLiteral.offset, fLiteral.length); 1589 fStringBuffer2.append(fLiteral2.ch, fLiteral2.offset, fLiteral2.length); 1590 } 1591 1592 // skip possible trailing space 1593 skipSeparator(false, !scanningInternalSubset()); 1594 1595 // end 1596 if (!fEntityScanner.skipChar('>', null)) { 1597 reportFatalError("EntityDeclUnterminated", new Object[]{name}); 1598 } 1599 fMarkUpDepth--; 1600 1601 // register entity and make callback 1602 if (isPEDecl) { 1603 name = "%" + name; 1604 } 1605 if (systemId != null) { 1606 String baseSystemId = fEntityScanner.getBaseSystemId(); 1607 if (notation != null) { 1608 fEntityStore.addUnparsedEntity(name, publicId, systemId, baseSystemId, notation); 1609 } 1610 else { 1611 fEntityStore.addExternalEntity(name, publicId, systemId, 1612 baseSystemId); 1613 } 1614 if (fDTDHandler != null) { 1615 //Venu Revisit : why false has been removed in expandSYstem 1616 fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId )); 1617 1618 if (notation != null) { 1619 fDTDHandler.unparsedEntityDecl(name, fResourceIdentifier, 1620 notation, null); 1621 } 1622 else { 1623 fDTDHandler.externalEntityDecl(name, fResourceIdentifier, null); 1624 } 1625 } 1626 } 1627 else { 1628 fEntityStore.addInternalEntity(name, fStringBuffer.toString()); 1629 if (fDTDHandler != null) { 1630 fDTDHandler.internalEntityDecl(name, fStringBuffer, fStringBuffer2, null); 1631 } 1632 } 1633 fReportEntity = true; 1634 1635 } // scanEntityDecl() 1636 1637 /** 1638 * Scans an entity value. 1639 * 1640 * @param value The string to fill in with the value. 1641 * @param nonNormalizedValue The string to fill in with the 1642 * non-normalized value. 1643 * 1644 * <strong>Note:</strong> This method uses fString, fStringBuffer (through 1645 * the use of scanCharReferenceValue), and fStringBuffer2, anything in them 1646 * at the time of calling is lost. 1647 */ 1648 protected final void scanEntityValue(String entityName, boolean isPEDecl, XMLString value, 1649 XMLString nonNormalizedValue) 1650 throws IOException, XNIException { 1651 int quote = fEntityScanner.scanChar(null); 1652 if (quote != '\'' && quote != '"') { 1653 reportFatalError("OpenQuoteMissingInDecl", null); 1654 } 1655 // store at which depth of entities we start 1656 int entityDepth = fEntityDepth; 1657 1658 XMLString literal = fString; 1659 XMLString literal2 = fString; 1660 int countChar = 0; 1661 if (fLimitAnalyzer == null ) { 1662 fLimitAnalyzer = fEntityManager.fLimitAnalyzer; 1663 } 1664 fLimitAnalyzer.startEntity(entityName); 1665 1666 if (fEntityScanner.scanLiteral(quote, fString, false) != quote) { 1667 fStringBuffer.clear(); 1668 fStringBuffer2.clear(); 1669 int offset; 1670 do { 1671 countChar = 0; 1672 offset = fStringBuffer.length; 1673 fStringBuffer.append(fString); 1674 fStringBuffer2.append(fString); 1675 if (fEntityScanner.skipChar('&', NameType.REFERENCE)) { 1676 if (fEntityScanner.skipChar('#', NameType.REFERENCE)) { 1677 fStringBuffer2.append("&#"); 1678 scanCharReferenceValue(fStringBuffer, fStringBuffer2); 1679 } 1680 else { 1681 fStringBuffer.append('&'); 1682 fStringBuffer2.append('&'); 1683 String eName = fEntityScanner.scanName(NameType.REFERENCE); 1684 if (eName == null) { 1685 reportFatalError("NameRequiredInReference", 1686 null); 1687 } 1688 else { 1689 fStringBuffer.append(eName); 1690 fStringBuffer2.append(eName); 1691 } 1692 if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) { 1693 reportFatalError("SemicolonRequiredInReference", 1694 new Object[]{eName}); 1695 } 1696 else { 1697 fStringBuffer.append(';'); 1698 fStringBuffer2.append(';'); 1699 } 1700 } 1701 } 1702 else if (fEntityScanner.skipChar('%', NameType.REFERENCE)) { 1703 while (true) { 1704 fStringBuffer2.append('%'); 1705 String peName = fEntityScanner.scanName(NameType.REFERENCE); 1706 if (peName == null) { 1707 reportFatalError("NameRequiredInPEReference", 1708 null); 1709 } 1710 else if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) { 1711 reportFatalError("SemicolonRequiredInPEReference", 1712 new Object[]{peName}); 1713 } 1714 else { 1715 if (scanningInternalSubset()) { 1716 reportFatalError("PEReferenceWithinMarkup", 1717 new Object[]{peName}); 1718 } 1719 fStringBuffer2.append(peName); 1720 fStringBuffer2.append(';'); 1721 } 1722 startPE(peName, true); 1723 // REVISIT: [Q] Why do we skip spaces here? -Ac 1724 // REVISIT: This will make returning the non- 1725 // normalized value harder. -Ac 1726 fEntityScanner.skipSpaces(); 1727 if (!fEntityScanner.skipChar('%', NameType.REFERENCE)) 1728 break; 1729 } 1730 } 1731 else { 1732 int c = fEntityScanner.peekChar(); 1733 if (XMLChar.isHighSurrogate(c)) { 1734 countChar++; 1735 scanSurrogates(fStringBuffer2); 1736 } 1737 else if (isInvalidLiteral(c)) { 1738 reportFatalError("InvalidCharInLiteral", 1739 new Object[]{Integer.toHexString(c)}); 1740 fEntityScanner.scanChar(null); 1741 } 1742 // if it's not the delimiting quote or if it is but from a 1743 // different entity than the one this literal started from, 1744 // simply append the character to our buffer 1745 else if (c != quote || entityDepth != fEntityDepth) { 1746 fStringBuffer.append((char)c); 1747 fStringBuffer2.append((char)c); 1748 fEntityScanner.scanChar(null); 1749 } 1750 } 1751 checkEntityLimit(isPEDecl, entityName, fStringBuffer.length - offset + countChar); 1752 } while (fEntityScanner.scanLiteral(quote, fString, false) != quote); 1753 checkEntityLimit(isPEDecl, entityName, fString.length); 1754 fStringBuffer.append(fString); 1755 fStringBuffer2.append(fString); 1756 literal = fStringBuffer; 1757 literal2 = fStringBuffer2; 1758 } else { 1759 checkEntityLimit(isPEDecl, entityName, literal); 1760 } 1761 value.setValues(literal); 1762 nonNormalizedValue.setValues(literal2); 1763 if (fLimitAnalyzer != null) { 1764 if (isPEDecl) { 1765 fLimitAnalyzer.endEntity(XMLSecurityManager.Limit.PARAMETER_ENTITY_SIZE_LIMIT, entityName); 1766 } else { 1767 fLimitAnalyzer.endEntity(XMLSecurityManager.Limit.GENERAL_ENTITY_SIZE_LIMIT, entityName); 1768 } 1769 } 1770 1771 if (!fEntityScanner.skipChar(quote, null)) { 1772 reportFatalError("CloseQuoteMissingInDecl", null); 1773 } 1774 } // scanEntityValue(XMLString,XMLString):void 1775 1776 /** 1777 * Scans a notation declaration 1778 * <p> 1779 * <pre> 1780 * [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID|PublicID) S? '>' 1781 * [83] PublicID ::= 'PUBLIC' S PubidLiteral 1782 * </pre> 1783 * <p> 1784 * <strong>Note:</strong> Called after scanning past '<!NOTATION' 1785 */ 1786 private final void scanNotationDecl() throws IOException, XNIException { 1787 1788 // spaces 1789 fReportEntity = false; 1790 if (!skipSeparator(true, !scanningInternalSubset())) { 1791 reportFatalError("MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_NOTATIONDECL", 1792 null); 1793 } 1794 1795 // notation name 1796 String name = fEntityScanner.scanName(NameType.NOTATION); 1797 if (name == null) { 1798 reportFatalError("MSG_NOTATION_NAME_REQUIRED_IN_NOTATIONDECL", 1799 null); 1800 } 1801 1802 // spaces 1803 if (!skipSeparator(true, !scanningInternalSubset())) { 1804 reportFatalError("MSG_SPACE_REQUIRED_AFTER_NOTATION_NAME_IN_NOTATIONDECL", 1805 new Object[]{name}); 1806 } 1807 1808 // external id 1809 scanExternalID(fStrings, true); 1810 String systemId = fStrings[0]; 1811 String publicId = fStrings[1]; 1812 String baseSystemId = fEntityScanner.getBaseSystemId(); 1813 1814 if (systemId == null && publicId == null) { 1815 reportFatalError("ExternalIDorPublicIDRequired", 1816 new Object[]{name}); 1817 } 1818 1819 // skip possible trailing space 1820 skipSeparator(false, !scanningInternalSubset()); 1821 1822 // end 1823 if (!fEntityScanner.skipChar('>', null)) { 1824 reportFatalError("NotationDeclUnterminated", new Object[]{name}); 1825 } 1826 fMarkUpDepth--; 1827 1828 fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId )); 1829 if (nonValidatingMode) nvGrammarInfo.notationDecl(name, fResourceIdentifier, null); 1830 // call handler 1831 if (fDTDHandler != null) { 1832 //Venu Revisit wby false has been removed. 1833 //fResourceIdentifier.setValues(publicId, systemId, baseSystemId, XMLEntityManager.expandSystemId(systemId, baseSystemId, false)); 1834 fDTDHandler.notationDecl(name, fResourceIdentifier, null); 1835 } 1836 fReportEntity = true; 1837 1838 } // scanNotationDecl() 1839 1840 /** 1841 * Scans a conditional section. If it's a section to ignore the whole 1842 * section gets scanned through and this method only returns after the 1843 * closing bracket has been found. When it's an include section though, it 1844 * returns to let the main loop take care of scanning it. In that case the 1845 * end of the section if handled by the main loop (scanDecls). 1846 * <p> 1847 * <pre> 1848 * [61] conditionalSect ::= includeSect | ignoreSect 1849 * [62] includeSect ::= '<![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>' 1850 * [63] ignoreSect ::= '<![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>' 1851 * [64] ignoreSectContents ::= Ignore ('<![' ignoreSectContents ']]>' Ignore)* 1852 * [65] Ignore ::= Char* - (Char* ('<![' | ']]>') Char*) 1853 * </pre> 1854 * <p> 1855 * <strong>Note:</strong> Called after scanning past '<![' */ 1856 private final void scanConditionalSect(int currPEDepth) 1857 throws IOException, XNIException { 1858 1859 fReportEntity = false; 1860 skipSeparator(false, !scanningInternalSubset()); 1861 1862 if (fEntityScanner.skipString("INCLUDE")) { 1863 skipSeparator(false, !scanningInternalSubset()); 1864 if(currPEDepth != fPEDepth && fValidation) { 1865 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1866 "INVALID_PE_IN_CONDITIONAL", 1867 new Object[]{ fEntityManager.fCurrentEntity.name}, 1868 XMLErrorReporter.SEVERITY_ERROR); 1869 } 1870 // call handler 1871 if (!fEntityScanner.skipChar('[', null)) { 1872 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null); 1873 } 1874 1875 if (fDTDHandler != null) { 1876 fDTDHandler.startConditional(XMLDTDHandler.CONDITIONAL_INCLUDE, 1877 null); 1878 } 1879 fIncludeSectDepth++; 1880 // just stop there and go back to the main loop 1881 fReportEntity = true; 1882 } 1883 else if (fEntityScanner.skipString("IGNORE")) { 1884 skipSeparator(false, !scanningInternalSubset()); 1885 if(currPEDepth != fPEDepth && fValidation) { 1886 fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN, 1887 "INVALID_PE_IN_CONDITIONAL", 1888 new Object[]{ fEntityManager.fCurrentEntity.name}, 1889 XMLErrorReporter.SEVERITY_ERROR); 1890 } 1891 // call handler 1892 if (fDTDHandler != null) { 1893 fDTDHandler.startConditional(XMLDTDHandler.CONDITIONAL_IGNORE, 1894 null); 1895 } 1896 if (!fEntityScanner.skipChar('[', null)) { 1897 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null); 1898 } 1899 fReportEntity = true; 1900 int initialDepth = ++fIncludeSectDepth; 1901 if (fDTDHandler != null) { 1902 fIgnoreConditionalBuffer.clear(); 1903 } 1904 while (true) { 1905 if (fEntityScanner.skipChar('<', null)) { 1906 if (fDTDHandler != null) { 1907 fIgnoreConditionalBuffer.append('<'); 1908 } 1909 // 1910 // These tests are split so that we handle cases like 1911 // '<<![' and '<!<![' which we might otherwise miss. 1912 // 1913 if (fEntityScanner.skipChar('!', null)) { 1914 if(fEntityScanner.skipChar('[', null)) { 1915 if (fDTDHandler != null) { 1916 fIgnoreConditionalBuffer.append("!["); 1917 } 1918 fIncludeSectDepth++; 1919 } else { 1920 if (fDTDHandler != null) { 1921 fIgnoreConditionalBuffer.append("!"); 1922 } 1923 } 1924 } 1925 } 1926 else if (fEntityScanner.skipChar(']', null)) { 1927 if (fDTDHandler != null) { 1928 fIgnoreConditionalBuffer.append(']'); 1929 } 1930 // 1931 // The same thing goes for ']<![' and '<]]>', etc. 1932 // 1933 if (fEntityScanner.skipChar(']', null)) { 1934 if (fDTDHandler != null) { 1935 fIgnoreConditionalBuffer.append(']'); 1936 } 1937 while (fEntityScanner.skipChar(']', null)) { 1938 /* empty loop body */ 1939 if (fDTDHandler != null) { 1940 fIgnoreConditionalBuffer.append(']'); 1941 } 1942 } 1943 if (fEntityScanner.skipChar('>', null)) { 1944 if (fIncludeSectDepth-- == initialDepth) { 1945 fMarkUpDepth--; 1946 // call handler 1947 if (fDTDHandler != null) { 1948 fLiteral.setValues(fIgnoreConditionalBuffer.ch, 0, 1949 fIgnoreConditionalBuffer.length - 2); 1950 fDTDHandler.ignoredCharacters(fLiteral, null); 1951 fDTDHandler.endConditional(null); 1952 } 1953 return; 1954 } else if(fDTDHandler != null) { 1955 fIgnoreConditionalBuffer.append('>'); 1956 } 1957 } 1958 } 1959 } 1960 else { 1961 int c = fEntityScanner.scanChar(null); 1962 if (fScannerState == SCANNER_STATE_END_OF_INPUT) { 1963 reportFatalError("IgnoreSectUnterminated", null); 1964 return; 1965 } 1966 if (fDTDHandler != null) { 1967 fIgnoreConditionalBuffer.append((char)c); 1968 } 1969 } 1970 } 1971 } 1972 else { 1973 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null); 1974 } 1975 1976 } // scanConditionalSect() 1977 1978 /** 1979 * Dispatch an XML "event". 1980 * 1981 * @param complete True if this method is intended to scan 1982 * and dispatch as much as possible. 1983 * 1984 * @return True if there is more to scan. 1985 * 1986 * @throws IOException Thrown on i/o error. 1987 * @throws XNIException Thrown on parse error. 1988 * 1989 */ 1990 protected final boolean scanDecls(boolean complete) 1991 throws IOException, XNIException { 1992 1993 skipSeparator(false, true); 1994 boolean again = true; 1995 //System.out.println("scanDecls"+fScannerState); 1996 while (again && fScannerState == SCANNER_STATE_MARKUP_DECL) { 1997 again = complete; 1998 if (fEntityScanner.skipChar('<', null)) { 1999 fMarkUpDepth++; 2000 if (fEntityScanner.skipChar('?', null)) { 2001 fStringBuffer.clear(); 2002 scanPI(fStringBuffer); 2003 fMarkUpDepth--; // we're done with this decl 2004 } 2005 else if (fEntityScanner.skipChar('!', null)) { 2006 if (fEntityScanner.skipChar('-', null)) { 2007 if (!fEntityScanner.skipChar('-', null)) { 2008 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", 2009 null); 2010 } else { 2011 scanComment(); 2012 } 2013 } 2014 else if (fEntityScanner.skipString("ELEMENT")) { 2015 scanElementDecl(); 2016 } 2017 else if (fEntityScanner.skipString("ATTLIST")) { 2018 scanAttlistDecl(); 2019 } 2020 else if (fEntityScanner.skipString("ENTITY")) { 2021 scanEntityDecl(); 2022 } 2023 else if (fEntityScanner.skipString("NOTATION")) { 2024 scanNotationDecl(); 2025 } 2026 else if (fEntityScanner.skipChar('[', null) && 2027 !scanningInternalSubset()) { 2028 scanConditionalSect(fPEDepth); 2029 } 2030 else { 2031 fMarkUpDepth--; 2032 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", 2033 null); 2034 } 2035 } 2036 else { 2037 fMarkUpDepth--; 2038 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null); 2039 } 2040 } 2041 else if (fIncludeSectDepth > 0 && fEntityScanner.skipChar(']', null)) { 2042 // end of conditional section? 2043 if (!fEntityScanner.skipChar(']', null) 2044 || !fEntityScanner.skipChar('>', null)) { 2045 reportFatalError("IncludeSectUnterminated", null); 2046 } 2047 // call handler 2048 if (fDTDHandler != null) { 2049 fDTDHandler.endConditional(null); 2050 } 2051 // decreaseMarkupDepth(); 2052 fIncludeSectDepth--; 2053 fMarkUpDepth--; 2054 } 2055 else if (scanningInternalSubset() && 2056 fEntityScanner.peekChar() == ']') { 2057 // this is the end of the internal subset, let's stop here 2058 return false; 2059 } 2060 else if (fEntityScanner.skipSpaces()) { 2061 // simply skip 2062 } 2063 else { 2064 reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null); 2065 } 2066 skipSeparator(false, true); 2067 } 2068 return fScannerState != SCANNER_STATE_END_OF_INPUT; 2069 } 2070 2071 /** 2072 * Skip separator. This is typically just whitespace but it can also be one 2073 * or more parameter entity references. 2074 * <p> 2075 * If there are some it "expands them" by calling the corresponding entity 2076 * from the entity manager. 2077 * <p> 2078 * This is recursive and will process has many refs as possible. 2079 * 2080 * @param spaceRequired Specify whether some leading whitespace should be 2081 * found 2082 * @param lookForPERefs Specify whether parameter entity references should 2083 * be looked for 2084 * @return True if any leading whitespace was found or the end of a 2085 * parameter entity was crossed. 2086 */ 2087 private boolean skipSeparator(boolean spaceRequired, boolean lookForPERefs) 2088 throws IOException, XNIException { 2089 int depth = fPEDepth; 2090 boolean sawSpace = fEntityScanner.skipSpaces(); 2091 if (!lookForPERefs || !fEntityScanner.skipChar('%', NameType.REFERENCE)) { 2092 return !spaceRequired || sawSpace || (depth != fPEDepth); 2093 } 2094 while (true) { 2095 String name = fEntityScanner.scanName(NameType.ENTITY); 2096 if (name == null) { 2097 reportFatalError("NameRequiredInPEReference", null); 2098 } 2099 else if (!fEntityScanner.skipChar(';', NameType.REFERENCE)) { 2100 reportFatalError("SemicolonRequiredInPEReference", 2101 new Object[]{name}); 2102 } 2103 startPE(name, false); 2104 fEntityScanner.skipSpaces(); 2105 if (!fEntityScanner.skipChar('%', NameType.REFERENCE)) 2106 return true; 2107 } 2108 } 2109 2110 2111 /* 2112 * Element Children Content Stack 2113 */ 2114 private final void pushContentStack(int c) { 2115 if (fContentStack.length == fContentDepth) { 2116 int[] newStack = new int[fContentDepth * 2]; 2117 System.arraycopy(fContentStack, 0, newStack, 0, fContentDepth); 2118 fContentStack = newStack; 2119 } 2120 fContentStack[fContentDepth++] = c; 2121 } 2122 2123 private final int popContentStack() { 2124 return fContentStack[--fContentDepth]; 2125 } 2126 2127 2128 /* 2129 * Parameter Entity Stack 2130 */ 2131 private final void pushPEStack(int depth, boolean report) { 2132 if (fPEStack.length == fPEDepth) { 2133 int[] newIntStack = new int[fPEDepth * 2]; 2134 System.arraycopy(fPEStack, 0, newIntStack, 0, fPEDepth); 2135 fPEStack = newIntStack; 2136 // report end/start calls 2137 boolean[] newBooleanStack = new boolean[fPEDepth * 2]; 2138 System.arraycopy(fPEReport, 0, newBooleanStack, 0, fPEDepth); 2139 fPEReport = newBooleanStack; 2140 2141 } 2142 fPEReport[fPEDepth] = report; 2143 fPEStack[fPEDepth++] = depth; 2144 } 2145 2146 /** pop the stack */ 2147 private final int popPEStack() { 2148 return fPEStack[--fPEDepth]; 2149 } 2150 2151 /** look at the top of the stack */ 2152 private final boolean peekReportEntity() { 2153 return fPEReport[fPEDepth-1]; 2154 } 2155 2156 2157 /* 2158 * Utility method 2159 */ 2160 private final void ensureEnumerationSize(int size) { 2161 if (fEnumeration.length == size) { 2162 String[] newEnum = new String[size * 2]; 2163 System.arraycopy(fEnumeration, 0, newEnum, 0, size); 2164 fEnumeration = newEnum; 2165 } 2166 } 2167 2168 // private methods 2169 private void init() { 2170 // reset state related data 2171 fStartDTDCalled = false; 2172 fExtEntityDepth = 0; 2173 fIncludeSectDepth = 0; 2174 fMarkUpDepth = 0; 2175 fPEDepth = 0; 2176 2177 fStandalone = false; 2178 fSeenExternalDTD = false; 2179 fSeenExternalPE = false; 2180 2181 // set starting state 2182 setScannerState(SCANNER_STATE_TEXT_DECL); 2183 //new SymbolTable()); 2184 2185 fLimitAnalyzer = fEntityManager.fLimitAnalyzer; 2186 fSecurityManager = fEntityManager.fSecurityManager; 2187 } 2188 2189 public DTDGrammar getGrammar(){ 2190 return nvGrammarInfo; 2191 } 2192 2193} // class XMLDTDScannerImpl 2194