Source Code Cross Referenced for XMLDTDScannerImpl.java in  » XML » xerces-2_9_1 » org » apache » xerces » impl » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » XML » xerces 2_9_1 » org.apache.xerces.impl 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Licensed to the Apache Software Foundation (ASF) under one or more
0003:         * contributor license agreements.  See the NOTICE file distributed with
0004:         * this work for additional information regarding copyright ownership.
0005:         * The ASF licenses this file to You under the Apache License, Version 2.0
0006:         * (the "License"); you may not use this file except in compliance with
0007:         * the License.  You may obtain a copy of the License at
0008:         * 
0009:         *      http://www.apache.org/licenses/LICENSE-2.0
0010:         * 
0011:         * Unless required by applicable law or agreed to in writing, software
0012:         * distributed under the License is distributed on an "AS IS" BASIS,
0013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014:         * See the License for the specific language governing permissions and
0015:         * limitations under the License.
0016:         */
0017:
0018:        package org.apache.xerces.impl;
0019:
0020:        import java.io.IOException;
0021:
0022:        import org.apache.xerces.impl.msg.XMLMessageFormatter;
0023:        import org.apache.xerces.util.SymbolTable;
0024:        import org.apache.xerces.util.XMLChar;
0025:        import org.apache.xerces.util.XMLStringBuffer;
0026:        import org.apache.xerces.util.XMLSymbols;
0027:        import org.apache.xerces.xni.Augmentations;
0028:        import org.apache.xerces.xni.XMLDTDContentModelHandler;
0029:        import org.apache.xerces.xni.XMLDTDHandler;
0030:        import org.apache.xerces.xni.XMLResourceIdentifier;
0031:        import org.apache.xerces.xni.XMLString;
0032:        import org.apache.xerces.xni.XNIException;
0033:        import org.apache.xerces.xni.parser.XMLComponent;
0034:        import org.apache.xerces.xni.parser.XMLComponentManager;
0035:        import org.apache.xerces.xni.parser.XMLConfigurationException;
0036:        import org.apache.xerces.xni.parser.XMLDTDScanner;
0037:        import org.apache.xerces.xni.parser.XMLInputSource;
0038:
0039:        /**
0040:         * This class is responsible for scanning the declarations found
0041:         * in the internal and external subsets of a DTD in an XML document.
0042:         * The scanner acts as the sources for the DTD information which is 
0043:         * communicated to the DTD handlers.
0044:         * <p>
0045:         * This component requires the following features and properties from the
0046:         * component manager that uses it:
0047:         * <ul>
0048:         *  <li>http://xml.org/sax/features/validation</li>
0049:         *  <li>http://apache.org/xml/features/scanner/notify-char-refs</li>
0050:         *  <li>http://apache.org/xml/properties/internal/symbol-table</li>
0051:         *  <li>http://apache.org/xml/properties/internal/error-reporter</li>
0052:         *  <li>http://apache.org/xml/properties/internal/entity-manager</li>
0053:         * </ul>
0054:         * 
0055:         * @xerces.internal
0056:         *
0057:         * @author Arnaud  Le Hors, IBM
0058:         * @author Andy Clark, IBM
0059:         * @author Glenn Marcy, IBM
0060:         * @author Eric Ye, IBM
0061:         *
0062:         * @version $Id: XMLDTDScannerImpl.java 572055 2007-09-02 17:55:43Z mrglavas $
0063:         */
0064:        public class XMLDTDScannerImpl extends XMLScanner implements 
0065:                XMLDTDScanner, XMLComponent, XMLEntityHandler {
0066:
0067:            //
0068:            // Constants
0069:            //
0070:
0071:            // scanner states
0072:
0073:            /** Scanner state: end of input. */
0074:            protected static final int SCANNER_STATE_END_OF_INPUT = 0;
0075:
0076:            /** Scanner state: text declaration. */
0077:            protected static final int SCANNER_STATE_TEXT_DECL = 1;
0078:
0079:            /** Scanner state: markup declaration. */
0080:            protected static final int SCANNER_STATE_MARKUP_DECL = 2;
0081:
0082:            // recognized features and properties
0083:
0084:            /** Recognized features. */
0085:            private static final String[] RECOGNIZED_FEATURES = { VALIDATION,
0086:                    NOTIFY_CHAR_REFS, };
0087:
0088:            /** Feature defaults. */
0089:            private static final Boolean[] FEATURE_DEFAULTS = { null,
0090:                    Boolean.FALSE, };
0091:
0092:            /** Recognized properties. */
0093:            private static final String[] RECOGNIZED_PROPERTIES = {
0094:                    SYMBOL_TABLE, ERROR_REPORTER, ENTITY_MANAGER, };
0095:
0096:            /** Property defaults. */
0097:            private static final Object[] PROPERTY_DEFAULTS = { null, null,
0098:                    null, };
0099:
0100:            // debugging
0101:
0102:            /** Debug scanner state. */
0103:            private static final boolean DEBUG_SCANNER_STATE = false;
0104:
0105:            //
0106:            // Data
0107:            //
0108:
0109:            // handlers
0110:
0111:            /** DTD handler. */
0112:            protected XMLDTDHandler fDTDHandler;
0113:
0114:            /** DTD content model handler. */
0115:            protected XMLDTDContentModelHandler fDTDContentModelHandler;
0116:
0117:            // state
0118:
0119:            /** Scanner state. */
0120:            protected int fScannerState;
0121:
0122:            /** Standalone. */
0123:            protected boolean fStandalone;
0124:
0125:            /** Seen external DTD. */
0126:            protected boolean fSeenExternalDTD;
0127:
0128:            /** Seen a parameter entity reference. */
0129:            protected boolean fSeenPEReferences;
0130:
0131:            // private data
0132:
0133:            /** Start DTD called. */
0134:            private boolean fStartDTDCalled;
0135:
0136:            /** 
0137:             * Stack of content operators (either '|' or ',') in children 
0138:             * content.
0139:             */
0140:            private int[] fContentStack = new int[5];
0141:
0142:            /** Size of content stack. */
0143:            private int fContentDepth;
0144:
0145:            /** Parameter entity stack to check well-formedness. */
0146:            private int[] fPEStack = new int[5];
0147:
0148:            /** Parameter entity stack to report start/end entity calls. */
0149:            private boolean[] fPEReport = new boolean[5];
0150:
0151:            /** Number of opened parameter entities. */
0152:            private int fPEDepth;
0153:
0154:            /** Markup depth. */
0155:            private int fMarkUpDepth;
0156:
0157:            /** Number of opened external entities. */
0158:            private int fExtEntityDepth;
0159:
0160:            /** Number of opened include sections. */
0161:            private int fIncludeSectDepth;
0162:
0163:            // temporary variables
0164:
0165:            /** Array of 3 strings. */
0166:            private final String[] fStrings = new String[3];
0167:
0168:            /** String. */
0169:            private final XMLString fString = new XMLString();
0170:
0171:            /** String buffer. */
0172:            private final XMLStringBuffer fStringBuffer = new XMLStringBuffer();
0173:
0174:            /** String buffer. */
0175:            private final XMLStringBuffer fStringBuffer2 = new XMLStringBuffer();
0176:
0177:            /** Literal text. */
0178:            private final XMLString fLiteral = new XMLString();
0179:
0180:            /** Literal text. */
0181:            private final XMLString fLiteral2 = new XMLString();
0182:
0183:            /** Enumeration values. */
0184:            private String[] fEnumeration = new String[5];
0185:
0186:            /** Enumeration values count. */
0187:            private int fEnumerationCount;
0188:
0189:            /** Ignore conditional section buffer. */
0190:            private final XMLStringBuffer fIgnoreConditionalBuffer = new XMLStringBuffer(
0191:                    128);
0192:
0193:            //
0194:            // Constructors
0195:            //
0196:
0197:            /** Default constructor. */
0198:            public XMLDTDScannerImpl() {
0199:            } // <init>()
0200:
0201:            /** Constructor for he use of non-XMLComponentManagers. */
0202:            public XMLDTDScannerImpl(SymbolTable symbolTable,
0203:                    XMLErrorReporter errorReporter,
0204:                    XMLEntityManager entityManager) {
0205:                fSymbolTable = symbolTable;
0206:                fErrorReporter = errorReporter;
0207:                fEntityManager = entityManager;
0208:                entityManager.setProperty(SYMBOL_TABLE, fSymbolTable);
0209:            }
0210:
0211:            //
0212:            // XMLDTDScanner methods
0213:            //
0214:
0215:            /** 
0216:             * Sets the input source. 
0217:             *
0218:             * @param inputSource The input source or null.
0219:             *
0220:             * @throws IOException Thrown on i/o error.
0221:             */
0222:            public void setInputSource(XMLInputSource inputSource)
0223:                    throws IOException {
0224:                if (inputSource == null) {
0225:                    // no system id was available
0226:                    if (fDTDHandler != null) {
0227:                        fDTDHandler.startDTD(null, null);
0228:                        fDTDHandler.endDTD(null);
0229:                    }
0230:                    return;
0231:                }
0232:                fEntityManager.setEntityHandler(this );
0233:                fEntityManager.startDTDEntity(inputSource);
0234:            } // setInputSource(XMLInputSource)
0235:
0236:            /**
0237:             * Scans the external subset of the document.
0238:             *
0239:             * @param complete True if the scanner should scan the document
0240:             *                 completely, pushing all events to the registered
0241:             *                 document handler. A value of false indicates that
0242:             *                 that the scanner should only scan the next portion
0243:             *                 of the document and return. A scanner instance is
0244:             *                 permitted to completely scan a document if it does
0245:             *                 not support this "pull" scanning model.
0246:             *
0247:             * @return True if there is more to scan, false otherwise.
0248:             */
0249:            public boolean scanDTDExternalSubset(boolean complete)
0250:                    throws IOException, XNIException {
0251:
0252:                fEntityManager.setEntityHandler(this );
0253:                if (fScannerState == SCANNER_STATE_TEXT_DECL) {
0254:                    fSeenExternalDTD = true;
0255:                    boolean textDecl = scanTextDecl();
0256:                    if (fScannerState == SCANNER_STATE_END_OF_INPUT) {
0257:                        return false;
0258:                    } else {
0259:                        // next state is markup decls regardless of whether there
0260:                        // is a TextDecl or not
0261:                        setScannerState(SCANNER_STATE_MARKUP_DECL);
0262:                        if (textDecl && !complete) {
0263:                            return true;
0264:                        }
0265:                    }
0266:                }
0267:                // keep dispatching "events"
0268:                do {
0269:                    if (!scanDecls(complete)) {
0270:                        return false;
0271:                    }
0272:                } while (complete);
0273:
0274:                // return that there is more to scan
0275:                return true;
0276:
0277:            } // scanDTDExternalSubset(boolean):boolean
0278:
0279:            /** 
0280:             * Scans the internal subset of the document.
0281:             *
0282:             * @param complete True if the scanner should scan the document
0283:             *                 completely, pushing all events to the registered
0284:             *                 document handler. A value of false indicates that
0285:             *                 that the scanner should only scan the next portion
0286:             *                 of the document and return. A scanner instance is
0287:             *                 permitted to completely scan a document if it does
0288:             *                 not support this "pull" scanning model.
0289:             * @param standalone True if the document was specified as standalone.
0290:             *                   This value is important for verifying certain
0291:             *                   well-formedness constraints.
0292:             * @param hasExternalSubset True if the document has an external DTD.
0293:             *                          This allows the scanner to properly notify
0294:             *                          the handler of the end of the DTD in the
0295:             *                          absence of an external subset.
0296:             *
0297:             * @return True if there is more to scan, false otherwise.
0298:             */
0299:            public boolean scanDTDInternalSubset(boolean complete,
0300:                    boolean standalone, boolean hasExternalSubset)
0301:                    throws IOException, XNIException {
0302:                // reset entity scanner
0303:                fEntityScanner = fEntityManager.getEntityScanner();
0304:                fEntityManager.setEntityHandler(this );
0305:                fStandalone = standalone;
0306:                if (fScannerState == SCANNER_STATE_TEXT_DECL) {
0307:                    // call handler
0308:                    if (fDTDHandler != null) {
0309:                        fDTDHandler.startDTD(fEntityScanner, null);
0310:                        fStartDTDCalled = true;
0311:                    }
0312:                    // set starting state for internal subset
0313:                    setScannerState(SCANNER_STATE_MARKUP_DECL);
0314:                }
0315:                // keep dispatching "events"
0316:                do {
0317:                    if (!scanDecls(complete)) {
0318:                        // call handler
0319:                        if (fDTDHandler != null && hasExternalSubset == false) {
0320:                            fDTDHandler.endDTD(null);
0321:                        }
0322:                        // we're done, set starting state for external subset
0323:                        setScannerState(SCANNER_STATE_TEXT_DECL);
0324:                        return false;
0325:                    }
0326:                } while (complete);
0327:
0328:                // return that there is more to scan
0329:                return true;
0330:
0331:            } // scanDTDInternalSubset(boolean,boolean,boolean):boolean
0332:
0333:            //
0334:            // XMLComponent methods
0335:            //
0336:
0337:            /**
0338:             * reset
0339:             * 
0340:             * @param componentManager 
0341:             */
0342:            public void reset(XMLComponentManager componentManager)
0343:                    throws XMLConfigurationException {
0344:
0345:                super .reset(componentManager);
0346:                init();
0347:
0348:            } // reset(XMLComponentManager)
0349:
0350:            // this is made for something like XMLDTDLoader--XMLComponentManager-free operation...
0351:            public void reset() {
0352:                super .reset();
0353:                init();
0354:            }
0355:
0356:            /**
0357:             * Returns a list of feature identifiers that are recognized by
0358:             * this component. This method may return null if no features
0359:             * are recognized by this component.
0360:             */
0361:            public String[] getRecognizedFeatures() {
0362:                return (String[]) (RECOGNIZED_FEATURES.clone());
0363:            } // getRecognizedFeatures():String[]
0364:
0365:            /**
0366:             * Returns a list of property identifiers that are recognized by
0367:             * this component. This method may return null if no properties
0368:             * are recognized by this component.
0369:             */
0370:            public String[] getRecognizedProperties() {
0371:                return (String[]) (RECOGNIZED_PROPERTIES.clone());
0372:            } // getRecognizedProperties():String[]
0373:
0374:            /** 
0375:             * Returns the default state for a feature, or null if this
0376:             * component does not want to report a default value for this
0377:             * feature.
0378:             *
0379:             * @param featureId The feature identifier.
0380:             *
0381:             * @since Xerces 2.2.0
0382:             */
0383:            public Boolean getFeatureDefault(String featureId) {
0384:                for (int i = 0; i < RECOGNIZED_FEATURES.length; i++) {
0385:                    if (RECOGNIZED_FEATURES[i].equals(featureId)) {
0386:                        return FEATURE_DEFAULTS[i];
0387:                    }
0388:                }
0389:                return null;
0390:            } // getFeatureDefault(String):Boolean
0391:
0392:            /** 
0393:             * Returns the default state for a property, or null if this
0394:             * component does not want to report a default value for this
0395:             * property. 
0396:             *
0397:             * @param propertyId The property identifier.
0398:             *
0399:             * @since Xerces 2.2.0
0400:             */
0401:            public Object getPropertyDefault(String propertyId) {
0402:                for (int i = 0; i < RECOGNIZED_PROPERTIES.length; i++) {
0403:                    if (RECOGNIZED_PROPERTIES[i].equals(propertyId)) {
0404:                        return PROPERTY_DEFAULTS[i];
0405:                    }
0406:                }
0407:                return null;
0408:            } // getPropertyDefault(String):Object
0409:
0410:            //
0411:            // XMLDTDSource methods
0412:            //
0413:
0414:            /**
0415:             * setDTDHandler
0416:             * 
0417:             * @param dtdHandler 
0418:             */
0419:            public void setDTDHandler(XMLDTDHandler dtdHandler) {
0420:                fDTDHandler = dtdHandler;
0421:            } // setDTDHandler(XMLDTDHandler)
0422:
0423:            /**
0424:             * getDTDHandler
0425:             * 
0426:             * @return the XMLDTDHandler
0427:             */
0428:            public XMLDTDHandler getDTDHandler() {
0429:                return fDTDHandler;
0430:            } // getDTDHandler():  XMLDTDHandler
0431:
0432:            //
0433:            // XMLDTDContentModelSource methods
0434:            //
0435:
0436:            /**
0437:             * setDTDContentModelHandler
0438:             * 
0439:             * @param dtdContentModelHandler 
0440:             */
0441:            public void setDTDContentModelHandler(
0442:                    XMLDTDContentModelHandler dtdContentModelHandler) {
0443:                fDTDContentModelHandler = dtdContentModelHandler;
0444:            } // setDTDContentModelHandler
0445:
0446:            /**
0447:             * getDTDContentModelHandler
0448:             * 
0449:             * @return XMLDTDContentModelHandler 
0450:             */
0451:            public XMLDTDContentModelHandler getDTDContentModelHandler() {
0452:                return fDTDContentModelHandler;
0453:            } // setDTDContentModelHandler
0454:
0455:            //
0456:            // XMLEntityHandler methods
0457:            //
0458:
0459:            /**
0460:             * This method notifies of the start of an entity. The DTD has the 
0461:             * pseudo-name of "[dtd]" parameter entity names start with '%'; and 
0462:             * general entities are just specified by their name.
0463:             * 
0464:             * @param name     The name of the entity.
0465:             * @param identifier The resource identifier.
0466:             * @param encoding The auto-detected IANA encoding name of the entity
0467:             *                 stream. This value will be null in those situations
0468:             *                 where the entity encoding is not auto-detected (e.g.
0469:             *                 internal entities or a document entity that is
0470:             *                 parsed from a java.io.Reader).
0471:             * @param augs     Additional information that may include infoset augmentations
0472:             *
0473:             * @throws XNIException Thrown by handler to signal an error.
0474:             */
0475:            public void startEntity(String name,
0476:                    XMLResourceIdentifier identifier, String encoding,
0477:                    Augmentations augs) throws XNIException {
0478:
0479:                super .startEntity(name, identifier, encoding, augs);
0480:
0481:                boolean dtdEntity = name.equals("[dtd]");
0482:                if (dtdEntity) {
0483:                    // call handler
0484:                    if (fDTDHandler != null && !fStartDTDCalled) {
0485:                        fDTDHandler.startDTD(fEntityScanner, null);
0486:                    }
0487:                    if (fDTDHandler != null) {
0488:                        fDTDHandler.startExternalSubset(identifier, null);
0489:                    }
0490:                    fEntityManager.startExternalSubset();
0491:                    fExtEntityDepth++;
0492:                } else if (name.charAt(0) == '%') {
0493:                    pushPEStack(fMarkUpDepth, fReportEntity);
0494:                    if (fEntityScanner.isExternal()) {
0495:                        fExtEntityDepth++;
0496:                    }
0497:                }
0498:
0499:                // call handler
0500:                if (fDTDHandler != null && !dtdEntity && fReportEntity) {
0501:                    fDTDHandler.startParameterEntity(name, identifier,
0502:                            encoding, augs);
0503:                }
0504:
0505:            } // startEntity(String,XMLResourceIdentifier,String)
0506:
0507:            /**
0508:             * This method notifies the end of an entity. The DTD has the pseudo-name
0509:             * of "[dtd]" parameter entity names start with '%'; and general entities 
0510:             * are just specified by their name.
0511:             * 
0512:             * @param name The name of the entity.
0513:             * @param augs Additional information that may include infoset augmentations
0514:             *
0515:             * @throws XNIException Thrown by handler to signal an error.
0516:             */
0517:            public void endEntity(String name, Augmentations augs)
0518:                    throws XNIException {
0519:
0520:                super .endEntity(name, augs);
0521:
0522:                // if there is no data after the doctype
0523:                //  
0524:                if (fScannerState == SCANNER_STATE_END_OF_INPUT)
0525:                    return;
0526:
0527:                // Handle end of PE
0528:                boolean reportEntity = fReportEntity;
0529:                if (name.startsWith("%")) {
0530:                    reportEntity = peekReportEntity();
0531:                    // check well-formedness of the enity
0532:                    int startMarkUpDepth = popPEStack();
0533:                    // throw fatalError if this entity was incomplete and
0534:                    // was a freestanding decl
0535:                    if (startMarkUpDepth == 0
0536:                            && startMarkUpDepth < fMarkUpDepth) {
0537:                        fErrorReporter
0538:                                .reportError(
0539:                                        XMLMessageFormatter.XML_DOMAIN,
0540:                                        "ILL_FORMED_PARAMETER_ENTITY_WHEN_USED_IN_DECL",
0541:                                        new Object[] { fEntityManager.fCurrentEntity.name },
0542:                                        XMLErrorReporter.SEVERITY_FATAL_ERROR);
0543:                    }
0544:                    if (startMarkUpDepth != fMarkUpDepth) {
0545:                        reportEntity = false;
0546:                        if (fValidation) {
0547:                            // Proper nesting of parameter entities is a Validity Constraint
0548:                            // and must not be enforced when validation is off
0549:                            fErrorReporter.reportError(
0550:                                    XMLMessageFormatter.XML_DOMAIN,
0551:                                    "ImproperDeclarationNesting",
0552:                                    new Object[] { name },
0553:                                    XMLErrorReporter.SEVERITY_ERROR);
0554:                        }
0555:                    }
0556:                    if (fEntityScanner.isExternal()) {
0557:                        fExtEntityDepth--;
0558:                    }
0559:                    // call handler
0560:                    if (fDTDHandler != null && reportEntity) {
0561:                        fDTDHandler.endParameterEntity(name, augs);
0562:                    }
0563:                }
0564:                // end DTD
0565:                else if (name.equals("[dtd]")) {
0566:                    if (fIncludeSectDepth != 0) {
0567:                        reportFatalError("IncludeSectUnterminated", null);
0568:                    }
0569:                    fScannerState = SCANNER_STATE_END_OF_INPUT;
0570:                    // call handler
0571:                    fEntityManager.endExternalSubset();
0572:                    if (fDTDHandler != null) {
0573:                        fDTDHandler.endExternalSubset(null);
0574:                        fDTDHandler.endDTD(null);
0575:                    }
0576:                    fExtEntityDepth--;
0577:                }
0578:
0579:            } // endEntity(String)
0580:
0581:            // helper methods
0582:
0583:            /**
0584:             * Sets the scanner state.
0585:             *
0586:             * @param state The new scanner state.
0587:             */
0588:            protected final void setScannerState(int state) {
0589:
0590:                fScannerState = state;
0591:                if (DEBUG_SCANNER_STATE) {
0592:                    System.out.print("### setScannerState: ");
0593:                    System.out.print(getScannerStateName(state));
0594:                    System.out.println();
0595:                }
0596:
0597:            } // setScannerState(int)
0598:
0599:            //
0600:            // Private methods
0601:            //
0602:
0603:            /** Returns the scanner state name. */
0604:            private static String getScannerStateName(int state) {
0605:
0606:                if (DEBUG_SCANNER_STATE) {
0607:                    switch (state) {
0608:                    case SCANNER_STATE_END_OF_INPUT:
0609:                        return "SCANNER_STATE_END_OF_INPUT";
0610:                    case SCANNER_STATE_TEXT_DECL:
0611:                        return "SCANNER_STATE_TEXT_DECL";
0612:                    case SCANNER_STATE_MARKUP_DECL:
0613:                        return "SCANNER_STATE_MARKUP_DECL";
0614:                    }
0615:                }
0616:
0617:                return "??? (" + state + ')';
0618:
0619:            } // getScannerStateName(int):String
0620:
0621:            protected final boolean scanningInternalSubset() {
0622:                return fExtEntityDepth == 0;
0623:            }
0624:
0625:            /**
0626:             * start a parameter entity dealing with the textdecl if there is any
0627:             *
0628:             * @param name The name of the parameter entity to start (without the '%')
0629:             * @param literal Whether this is happening within a literal
0630:             */
0631:            protected void startPE(String name, boolean literal)
0632:                    throws IOException, XNIException {
0633:                int depth = fPEDepth;
0634:                String pName = "%" + name;
0635:                if (!fSeenPEReferences) {
0636:                    fSeenPEReferences = true;
0637:                    fEntityManager.notifyHasPEReferences();
0638:                }
0639:                if (fValidation && !fEntityManager.isDeclaredEntity(pName)) {
0640:                    fErrorReporter.reportError(XMLMessageFormatter.XML_DOMAIN,
0641:                            "EntityNotDeclared", new Object[] { name },
0642:                            XMLErrorReporter.SEVERITY_ERROR);
0643:                }
0644:                fEntityManager.startEntity(fSymbolTable.addSymbol(pName),
0645:                        literal);
0646:                // if we actually got a new entity and it's external
0647:                // parse text decl if there is any
0648:                if (depth != fPEDepth && fEntityScanner.isExternal()) {
0649:                    scanTextDecl();
0650:                }
0651:            }
0652:
0653:            /** 
0654:             * Dispatch an XML "event".              
0655:             *
0656:             * @return true if a TextDecl was scanned.
0657:             *
0658:             * @throws IOException  Thrown on i/o error.
0659:             * @throws XNIException Thrown on parse error.
0660:             *
0661:             */
0662:            protected final boolean scanTextDecl() throws IOException,
0663:                    XNIException {
0664:
0665:                // scan XMLDecl
0666:                boolean textDecl = false;
0667:                if (fEntityScanner.skipString("<?xml")) {
0668:                    fMarkUpDepth++;
0669:                    // NOTE: special case where document starts with a PI
0670:                    //       whose name starts with "xml" (e.g. "xmlfoo")
0671:                    if (isValidNameChar(fEntityScanner.peekChar())) {
0672:                        fStringBuffer.clear();
0673:                        fStringBuffer.append("xml");
0674:                        if (fNamespaces) {
0675:                            while (isValidNCName(fEntityScanner.peekChar())) {
0676:                                fStringBuffer.append((char) fEntityScanner
0677:                                        .scanChar());
0678:                            }
0679:                        } else {
0680:                            while (isValidNameChar(fEntityScanner.peekChar())) {
0681:                                fStringBuffer.append((char) fEntityScanner
0682:                                        .scanChar());
0683:                            }
0684:                        }
0685:                        String target = fSymbolTable.addSymbol(
0686:                                fStringBuffer.ch, fStringBuffer.offset,
0687:                                fStringBuffer.length);
0688:                        scanPIData(target, fString);
0689:                    }
0690:
0691:                    // standard Text declaration
0692:                    else {
0693:                        // pseudo-attribute values
0694:                        String version = null;
0695:                        String encoding = null;
0696:
0697:                        scanXMLDeclOrTextDecl(true, fStrings);
0698:                        textDecl = true;
0699:                        fMarkUpDepth--;
0700:
0701:                        version = fStrings[0];
0702:                        encoding = fStrings[1];
0703:
0704:                        fEntityScanner.setXMLVersion(version);
0705:                        if (!fEntityScanner.fCurrentEntity
0706:                                .isEncodingExternallySpecified()) {
0707:                            fEntityScanner.setEncoding(encoding);
0708:                        }
0709:
0710:                        // call handler
0711:                        if (fDTDHandler != null) {
0712:                            fDTDHandler.textDecl(version, encoding, null);
0713:                        }
0714:                    }
0715:                }
0716:                fEntityManager.fCurrentEntity.mayReadChunks = true;
0717:
0718:                return textDecl;
0719:
0720:            } // scanTextDecl(boolean):boolean
0721:
0722:            /**
0723:             * Scans a processing data. This is needed to handle the situation
0724:             * where a document starts with a processing instruction whose 
0725:             * target name <em>starts with</em> "xml". (e.g. xmlfoo)
0726:             *
0727:             * @param target The PI target
0728:             * @param data The string to fill in with the data
0729:             */
0730:            protected final void scanPIData(String target, XMLString data)
0731:                    throws IOException, XNIException {
0732:
0733:                super .scanPIData(target, data);
0734:                fMarkUpDepth--;
0735:
0736:                // call handler
0737:                if (fDTDHandler != null) {
0738:                    fDTDHandler.processingInstruction(target, data, null);
0739:                }
0740:
0741:            } // scanPIData(String)
0742:
0743:            /**
0744:             * Scans a comment.
0745:             * <p>
0746:             * <pre>
0747:             * [15] Comment ::= '&lt!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
0748:             * </pre>
0749:             * <p>
0750:             * <strong>Note:</strong> Called after scanning past '&lt;!--'
0751:             */
0752:            protected final void scanComment() throws IOException, XNIException {
0753:
0754:                fReportEntity = false;
0755:                scanComment(fStringBuffer);
0756:                fMarkUpDepth--;
0757:
0758:                // call handler
0759:                if (fDTDHandler != null) {
0760:                    fDTDHandler.comment(fStringBuffer, null);
0761:                }
0762:                fReportEntity = true;
0763:
0764:            } // scanComment()
0765:
0766:            /**
0767:             * Scans an element declaration
0768:             * <p>
0769:             * <pre>
0770:             * [45]    elementdecl    ::=    '&lt;!ELEMENT' S Name S contentspec S? '>'
0771:             * [46]    contentspec    ::=    'EMPTY' | 'ANY' | Mixed | children  
0772:             * </pre>
0773:             * <p>
0774:             * <strong>Note:</strong> Called after scanning past '&lt;!ELEMENT'
0775:             */
0776:            protected final void scanElementDecl() throws IOException,
0777:                    XNIException {
0778:
0779:                // spaces
0780:                fReportEntity = false;
0781:                if (!skipSeparator(true, !scanningInternalSubset())) {
0782:                    reportFatalError(
0783:                            "MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ELEMENTDECL",
0784:                            null);
0785:                }
0786:
0787:                // element name
0788:                String name = fEntityScanner.scanName();
0789:                if (name == null) {
0790:                    reportFatalError(
0791:                            "MSG_ELEMENT_TYPE_REQUIRED_IN_ELEMENTDECL", null);
0792:                }
0793:
0794:                // spaces
0795:                if (!skipSeparator(true, !scanningInternalSubset())) {
0796:                    reportFatalError(
0797:                            "MSG_SPACE_REQUIRED_BEFORE_CONTENTSPEC_IN_ELEMENTDECL",
0798:                            new Object[] { name });
0799:                }
0800:
0801:                // content model
0802:                if (fDTDContentModelHandler != null) {
0803:                    fDTDContentModelHandler.startContentModel(name, null);
0804:                }
0805:                String contentModel = null;
0806:                fReportEntity = true;
0807:                if (fEntityScanner.skipString("EMPTY")) {
0808:                    contentModel = "EMPTY";
0809:                    // call handler
0810:                    if (fDTDContentModelHandler != null) {
0811:                        fDTDContentModelHandler.empty(null);
0812:                    }
0813:                } else if (fEntityScanner.skipString("ANY")) {
0814:                    contentModel = "ANY";
0815:                    // call handler
0816:                    if (fDTDContentModelHandler != null) {
0817:                        fDTDContentModelHandler.any(null);
0818:                    }
0819:                } else {
0820:                    if (!fEntityScanner.skipChar('(')) {
0821:                        reportFatalError(
0822:                                "MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN",
0823:                                new Object[] { name });
0824:                    }
0825:                    if (fDTDContentModelHandler != null) {
0826:                        fDTDContentModelHandler.startGroup(null);
0827:                    }
0828:                    fStringBuffer.clear();
0829:                    fStringBuffer.append('(');
0830:                    fMarkUpDepth++;
0831:                    skipSeparator(false, !scanningInternalSubset());
0832:
0833:                    // Mixed content model
0834:                    if (fEntityScanner.skipString("#PCDATA")) {
0835:                        scanMixed(name);
0836:                    } else { // children content
0837:                        scanChildren(name);
0838:                    }
0839:                    contentModel = fStringBuffer.toString();
0840:                }
0841:
0842:                // call handler
0843:                if (fDTDContentModelHandler != null) {
0844:                    fDTDContentModelHandler.endContentModel(null);
0845:                }
0846:
0847:                fReportEntity = false;
0848:                skipSeparator(false, !scanningInternalSubset());
0849:                // end
0850:                if (!fEntityScanner.skipChar('>')) {
0851:                    reportFatalError("ElementDeclUnterminated",
0852:                            new Object[] { name });
0853:                }
0854:                fReportEntity = true;
0855:                fMarkUpDepth--;
0856:
0857:                // call handler
0858:                if (fDTDHandler != null) {
0859:                    fDTDHandler.elementDecl(name, contentModel, null);
0860:                }
0861:
0862:            } // scanElementDecl()
0863:
0864:            /**
0865:             * scan Mixed content model
0866:             * This assumes the content model has been parsed up to #PCDATA and
0867:             * can simply append to fStringBuffer.
0868:             * <pre>
0869:             * [51]    Mixed    ::=    '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*'  
0870:             *                       | '(' S? '#PCDATA' S? ')'  
0871:             * </pre>
0872:             *
0873:             * @param elName The element type name this declaration is about.
0874:             *
0875:             * <strong>Note:</strong> Called after scanning past '(#PCDATA'.
0876:             */
0877:            private final void scanMixed(String elName) throws IOException,
0878:                    XNIException {
0879:
0880:                String childName = null;
0881:
0882:                fStringBuffer.append("#PCDATA");
0883:                // call handler
0884:                if (fDTDContentModelHandler != null) {
0885:                    fDTDContentModelHandler.pcdata(null);
0886:                }
0887:                skipSeparator(false, !scanningInternalSubset());
0888:                while (fEntityScanner.skipChar('|')) {
0889:                    fStringBuffer.append('|');
0890:                    // call handler
0891:                    if (fDTDContentModelHandler != null) {
0892:                        fDTDContentModelHandler.separator(
0893:                                XMLDTDContentModelHandler.SEPARATOR_CHOICE,
0894:                                null);
0895:                    }
0896:                    skipSeparator(false, !scanningInternalSubset());
0897:
0898:                    childName = fEntityScanner.scanName();
0899:                    if (childName == null) {
0900:                        reportFatalError(
0901:                                "MSG_ELEMENT_TYPE_REQUIRED_IN_MIXED_CONTENT",
0902:                                new Object[] { elName });
0903:                    }
0904:                    fStringBuffer.append(childName);
0905:                    // call handler
0906:                    if (fDTDContentModelHandler != null) {
0907:                        fDTDContentModelHandler.element(childName, null);
0908:                    }
0909:                    skipSeparator(false, !scanningInternalSubset());
0910:                }
0911:                // The following check must be done in a single call (as opposed to one
0912:                // for ')' and then one for '*') to guarantee that callbacks are
0913:                // properly nested. We do not want to trigger endEntity too early in
0914:                // case we cross the boundary of an entity between the two characters.
0915:                if (fEntityScanner.skipString(")*")) {
0916:                    fStringBuffer.append(")*");
0917:                    // call handler
0918:                    if (fDTDContentModelHandler != null) {
0919:                        fDTDContentModelHandler.endGroup(null);
0920:                        fDTDContentModelHandler.occurrence(
0921:                                XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE,
0922:                                null);
0923:                    }
0924:                } else if (childName != null) {
0925:                    reportFatalError("MixedContentUnterminated",
0926:                            new Object[] { elName });
0927:                } else if (fEntityScanner.skipChar(')')) {
0928:                    fStringBuffer.append(')');
0929:                    // call handler
0930:                    if (fDTDContentModelHandler != null) {
0931:                        fDTDContentModelHandler.endGroup(null);
0932:                    }
0933:                } else {
0934:                    reportFatalError("MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN",
0935:                            new Object[] { elName });
0936:                }
0937:                fMarkUpDepth--;
0938:                // we are done
0939:            }
0940:
0941:            /**
0942:             * scan children content model
0943:             * This assumes it can simply append to fStringBuffer.
0944:             * <pre>
0945:             * [47]    children  ::=    (choice | seq) ('?' | '*' | '+')? 
0946:             * [48]    cp        ::=    (Name | choice | seq) ('?' | '*' | '+')? 
0947:             * [49]    choice    ::=    '(' S? cp ( S? '|' S? cp )+ S? ')'
0948:             * [50]    seq       ::=    '(' S? cp ( S? ',' S? cp )* S? ')' 
0949:             * </pre>
0950:             *
0951:             * @param elName The element type name this declaration is about.
0952:             *
0953:             * <strong>Note:</strong> Called after scanning past the first open
0954:             * paranthesis.
0955:             */
0956:            private final void scanChildren(String elName) throws IOException,
0957:                    XNIException {
0958:
0959:                fContentDepth = 0;
0960:                pushContentStack(0);
0961:                int currentOp = 0;
0962:                int c;
0963:                while (true) {
0964:                    if (fEntityScanner.skipChar('(')) {
0965:                        fMarkUpDepth++;
0966:                        fStringBuffer.append('(');
0967:                        // call handler
0968:                        if (fDTDContentModelHandler != null) {
0969:                            fDTDContentModelHandler.startGroup(null);
0970:                        }
0971:                        // push current op on stack and reset it
0972:                        pushContentStack(currentOp);
0973:                        currentOp = 0;
0974:                        skipSeparator(false, !scanningInternalSubset());
0975:                        continue;
0976:                    }
0977:                    skipSeparator(false, !scanningInternalSubset());
0978:                    String childName = fEntityScanner.scanName();
0979:                    if (childName == null) {
0980:                        reportFatalError(
0981:                                "MSG_OPEN_PAREN_OR_ELEMENT_TYPE_REQUIRED_IN_CHILDREN",
0982:                                new Object[] { elName });
0983:                        return;
0984:                    }
0985:                    // call handler
0986:                    if (fDTDContentModelHandler != null) {
0987:                        fDTDContentModelHandler.element(childName, null);
0988:                    }
0989:                    fStringBuffer.append(childName);
0990:                    c = fEntityScanner.peekChar();
0991:                    if (c == '?' || c == '*' || c == '+') {
0992:                        // call handler
0993:                        if (fDTDContentModelHandler != null) {
0994:                            short oc;
0995:                            if (c == '?') {
0996:                                oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE;
0997:                            } else if (c == '*') {
0998:                                oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE;
0999:                            } else {
1000:                                oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE;
1001:                            }
1002:                            fDTDContentModelHandler.occurrence(oc, null);
1003:                        }
1004:                        fEntityScanner.scanChar();
1005:                        fStringBuffer.append((char) c);
1006:                    }
1007:                    while (true) {
1008:                        skipSeparator(false, !scanningInternalSubset());
1009:                        c = fEntityScanner.peekChar();
1010:                        if (c == ',' && currentOp != '|') {
1011:                            currentOp = c;
1012:                            // call handler
1013:                            if (fDTDContentModelHandler != null) {
1014:                                fDTDContentModelHandler
1015:                                        .separator(
1016:                                                XMLDTDContentModelHandler.SEPARATOR_SEQUENCE,
1017:                                                null);
1018:                            }
1019:                            fEntityScanner.scanChar();
1020:                            fStringBuffer.append(',');
1021:                            break;
1022:                        } else if (c == '|' && currentOp != ',') {
1023:                            currentOp = c;
1024:                            // call handler
1025:                            if (fDTDContentModelHandler != null) {
1026:                                fDTDContentModelHandler
1027:                                        .separator(
1028:                                                XMLDTDContentModelHandler.SEPARATOR_CHOICE,
1029:                                                null);
1030:                            }
1031:                            fEntityScanner.scanChar();
1032:                            fStringBuffer.append('|');
1033:                            break;
1034:                        } else if (c != ')') {
1035:                            reportFatalError(
1036:                                    "MSG_CLOSE_PAREN_REQUIRED_IN_CHILDREN",
1037:                                    new Object[] { elName });
1038:                        }
1039:                        // call handler
1040:                        if (fDTDContentModelHandler != null) {
1041:                            fDTDContentModelHandler.endGroup(null);
1042:                        }
1043:                        // restore previous op
1044:                        currentOp = popContentStack();
1045:                        short oc;
1046:                        // The following checks must be done in a single call (as
1047:                        // opposed to one for ')' and then one for '?', '*', and '+')
1048:                        // to guarantee that callbacks are properly nested. We do not
1049:                        // want to trigger endEntity too early in case we cross the
1050:                        // boundary of an entity between the two characters.
1051:                        if (fEntityScanner.skipString(")?")) {
1052:                            fStringBuffer.append(")?");
1053:                            // call handler
1054:                            if (fDTDContentModelHandler != null) {
1055:                                oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_ONE;
1056:                                fDTDContentModelHandler.occurrence(oc, null);
1057:                            }
1058:                        } else if (fEntityScanner.skipString(")+")) {
1059:                            fStringBuffer.append(")+");
1060:                            // call handler
1061:                            if (fDTDContentModelHandler != null) {
1062:                                oc = XMLDTDContentModelHandler.OCCURS_ONE_OR_MORE;
1063:                                fDTDContentModelHandler.occurrence(oc, null);
1064:                            }
1065:                        } else if (fEntityScanner.skipString(")*")) {
1066:                            fStringBuffer.append(")*");
1067:                            // call handler
1068:                            if (fDTDContentModelHandler != null) {
1069:                                oc = XMLDTDContentModelHandler.OCCURS_ZERO_OR_MORE;
1070:                                fDTDContentModelHandler.occurrence(oc, null);
1071:                            }
1072:                        } else {
1073:                            // no occurrence specified
1074:                            fEntityScanner.scanChar();
1075:                            fStringBuffer.append(')');
1076:                        }
1077:                        fMarkUpDepth--;
1078:                        if (fContentDepth == 0) {
1079:                            return;
1080:                        }
1081:                    }
1082:                    skipSeparator(false, !scanningInternalSubset());
1083:                }
1084:            }
1085:
1086:            /**
1087:             * Scans an attlist declaration
1088:             * <p>
1089:             * <pre>
1090:             * [52]  AttlistDecl    ::=   '&lt;!ATTLIST' S Name AttDef* S? '>' 
1091:             * [53]  AttDef         ::=   S Name S AttType S DefaultDecl 
1092:             * </pre>
1093:             * <p>
1094:             * <strong>Note:</strong> Called after scanning past '&lt;!ATTLIST'
1095:             */
1096:            protected final void scanAttlistDecl() throws IOException,
1097:                    XNIException {
1098:
1099:                // spaces
1100:                fReportEntity = false;
1101:                if (!skipSeparator(true, !scanningInternalSubset())) {
1102:                    reportFatalError(
1103:                            "MSG_SPACE_REQUIRED_BEFORE_ELEMENT_TYPE_IN_ATTLISTDECL",
1104:                            null);
1105:                }
1106:
1107:                // element name
1108:                String elName = fEntityScanner.scanName();
1109:                if (elName == null) {
1110:                    reportFatalError(
1111:                            "MSG_ELEMENT_TYPE_REQUIRED_IN_ATTLISTDECL", null);
1112:                }
1113:
1114:                // call handler
1115:                if (fDTDHandler != null) {
1116:                    fDTDHandler.startAttlist(elName, null);
1117:                }
1118:
1119:                // spaces
1120:                if (!skipSeparator(true, !scanningInternalSubset())) {
1121:                    // no space, is it the end yet?
1122:                    if (fEntityScanner.skipChar('>')) {
1123:                        // yes, stop here
1124:                        // call handler
1125:                        if (fDTDHandler != null) {
1126:                            fDTDHandler.endAttlist(null);
1127:                        }
1128:                        fMarkUpDepth--;
1129:                        return;
1130:                    } else {
1131:                        reportFatalError(
1132:                                "MSG_SPACE_REQUIRED_BEFORE_ATTRIBUTE_NAME_IN_ATTDEF",
1133:                                new Object[] { elName });
1134:                    }
1135:                }
1136:
1137:                // definitions
1138:                while (!fEntityScanner.skipChar('>')) {
1139:                    String name = fEntityScanner.scanName();
1140:                    if (name == null) {
1141:                        reportFatalError("AttNameRequiredInAttDef",
1142:                                new Object[] { elName });
1143:                    }
1144:                    // spaces
1145:                    if (!skipSeparator(true, !scanningInternalSubset())) {
1146:                        reportFatalError(
1147:                                "MSG_SPACE_REQUIRED_BEFORE_ATTTYPE_IN_ATTDEF",
1148:                                new Object[] { elName, name });
1149:                    }
1150:                    // type
1151:                    String type = scanAttType(elName, name);
1152:
1153:                    // spaces
1154:                    if (!skipSeparator(true, !scanningInternalSubset())) {
1155:                        reportFatalError(
1156:                                "MSG_SPACE_REQUIRED_BEFORE_DEFAULTDECL_IN_ATTDEF",
1157:                                new Object[] { elName, name });
1158:                    }
1159:
1160:                    // default decl
1161:                    String defaultType = scanAttDefaultDecl(elName, name, type,
1162:                            fLiteral, fLiteral2);
1163:                    // REVISIT: Should we do anything with the non-normalized
1164:                    //          default attribute value? -Ac
1165:                    // yes--according to bug 5073.  - neilg
1166:
1167:                    // call handler
1168:                    if (fDTDHandler != null) {
1169:                        String[] enumeration = null;
1170:                        if (fEnumerationCount != 0) {
1171:                            enumeration = new String[fEnumerationCount];
1172:                            System.arraycopy(fEnumeration, 0, enumeration, 0,
1173:                                    fEnumerationCount);
1174:                        }
1175:                        // Determine whether the default value to be passed should be null. 
1176:                        // REVISIT: should probably check whether fLiteral.ch is null instead. LM.
1177:                        if (defaultType != null
1178:                                && (defaultType.equals("#REQUIRED") || defaultType
1179:                                        .equals("#IMPLIED"))) {
1180:                            fDTDHandler.attributeDecl(elName, name, type,
1181:                                    enumeration, defaultType, null, null, null);
1182:                        } else {
1183:                            fDTDHandler.attributeDecl(elName, name, type,
1184:                                    enumeration, defaultType, fLiteral,
1185:                                    fLiteral2, null);
1186:                        }
1187:                    }
1188:                    skipSeparator(false, !scanningInternalSubset());
1189:                }
1190:
1191:                // call handler
1192:                if (fDTDHandler != null) {
1193:                    fDTDHandler.endAttlist(null);
1194:                }
1195:                fMarkUpDepth--;
1196:                fReportEntity = true;
1197:
1198:            } // scanAttlistDecl()
1199:
1200:            /**
1201:             * Scans an attribute type definition
1202:             * <p>
1203:             * <pre>
1204:             * [54]  AttType        ::=   StringType | TokenizedType | EnumeratedType  
1205:             * [55]  StringType     ::=   'CDATA' 
1206:             * [56]  TokenizedType  ::=   'ID'
1207:             *                          | 'IDREF'
1208:             *                          | 'IDREFS'
1209:             *                          | 'ENTITY'
1210:             *                          | 'ENTITIES'
1211:             *                          | 'NMTOKEN'
1212:             *                          | 'NMTOKENS'
1213:             * [57]  EnumeratedType ::=    NotationType | Enumeration  
1214:             * [58]  NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
1215:             * [59]  Enumeration    ::=    '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')' 
1216:             * </pre>
1217:             * <p>
1218:             * <strong>Note:</strong> Called after scanning past '&lt;!ATTLIST'
1219:             *
1220:             * @param elName The element type name this declaration is about.
1221:             * @param atName The attribute name this declaration is about.
1222:             */
1223:            private final String scanAttType(String elName, String atName)
1224:                    throws IOException, XNIException {
1225:
1226:                String type = null;
1227:                fEnumerationCount = 0;
1228:                /*
1229:                 * Watchout: the order here is important: when a string happens to
1230:                 * be a substring of another string, the longer one needs to be
1231:                 * looked for first!!
1232:                 */
1233:                if (fEntityScanner.skipString("CDATA")) {
1234:                    type = "CDATA";
1235:                } else if (fEntityScanner.skipString("IDREFS")) {
1236:                    type = "IDREFS";
1237:                } else if (fEntityScanner.skipString("IDREF")) {
1238:                    type = "IDREF";
1239:                } else if (fEntityScanner.skipString("ID")) {
1240:                    type = "ID";
1241:                } else if (fEntityScanner.skipString("ENTITY")) {
1242:                    type = "ENTITY";
1243:                } else if (fEntityScanner.skipString("ENTITIES")) {
1244:                    type = "ENTITIES";
1245:                } else if (fEntityScanner.skipString("NMTOKENS")) {
1246:                    type = "NMTOKENS";
1247:                } else if (fEntityScanner.skipString("NMTOKEN")) {
1248:                    type = "NMTOKEN";
1249:                } else if (fEntityScanner.skipString("NOTATION")) {
1250:                    type = "NOTATION";
1251:                    // spaces
1252:                    if (!skipSeparator(true, !scanningInternalSubset())) {
1253:                        reportFatalError(
1254:                                "MSG_SPACE_REQUIRED_AFTER_NOTATION_IN_NOTATIONTYPE",
1255:                                new Object[] { elName, atName });
1256:                    }
1257:                    // open paren
1258:                    int c = fEntityScanner.scanChar();
1259:                    if (c != '(') {
1260:                        reportFatalError(
1261:                                "MSG_OPEN_PAREN_REQUIRED_IN_NOTATIONTYPE",
1262:                                new Object[] { elName, atName });
1263:                    }
1264:                    fMarkUpDepth++;
1265:                    do {
1266:                        skipSeparator(false, !scanningInternalSubset());
1267:                        String aName = fEntityScanner.scanName();
1268:                        if (aName == null) {
1269:                            reportFatalError(
1270:                                    "MSG_NAME_REQUIRED_IN_NOTATIONTYPE",
1271:                                    new Object[] { elName, atName });
1272:                            c = skipInvalidEnumerationValue();
1273:                            if (c == '|') {
1274:                                continue;
1275:                            }
1276:                            break;
1277:                        }
1278:                        ensureEnumerationSize(fEnumerationCount + 1);
1279:                        fEnumeration[fEnumerationCount++] = aName;
1280:                        skipSeparator(false, !scanningInternalSubset());
1281:                        c = fEntityScanner.scanChar();
1282:                    } while (c == '|');
1283:                    if (c != ')') {
1284:                        reportFatalError("NotationTypeUnterminated",
1285:                                new Object[] { elName, atName });
1286:                    }
1287:                    fMarkUpDepth--;
1288:                } else { // Enumeration
1289:                    type = "ENUMERATION";
1290:                    // open paren
1291:                    int c = fEntityScanner.scanChar();
1292:                    if (c != '(') {
1293:                        //                       "OPEN_PAREN_REQUIRED_BEFORE_ENUMERATION_IN_ATTRDECL",
1294:                        reportFatalError("AttTypeRequiredInAttDef",
1295:                                new Object[] { elName, atName });
1296:                    }
1297:                    fMarkUpDepth++;
1298:                    do {
1299:                        skipSeparator(false, !scanningInternalSubset());
1300:                        String token = fEntityScanner.scanNmtoken();
1301:                        if (token == null) {
1302:                            reportFatalError(
1303:                                    "MSG_NMTOKEN_REQUIRED_IN_ENUMERATION",
1304:                                    new Object[] { elName, atName });
1305:                            c = skipInvalidEnumerationValue();
1306:                            if (c == '|') {
1307:                                continue;
1308:                            }
1309:                            break;
1310:                        }
1311:                        ensureEnumerationSize(fEnumerationCount + 1);
1312:                        fEnumeration[fEnumerationCount++] = token;
1313:                        skipSeparator(false, !scanningInternalSubset());
1314:                        c = fEntityScanner.scanChar();
1315:                    } while (c == '|');
1316:                    if (c != ')') {
1317:                        reportFatalError("EnumerationUnterminated",
1318:                                new Object[] { elName, atName });
1319:                    }
1320:                    fMarkUpDepth--;
1321:                }
1322:                return type;
1323:
1324:            } // scanAttType():String
1325:
1326:            /**
1327:             * Scans an attribute default declaration
1328:             * <p>
1329:             * <pre>
1330:             * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
1331:             * </pre>
1332:             *
1333:             * @param elName
1334:             * @param atName The name of the attribute being scanned.
1335:             * @param type
1336:             * @param defaultVal The string to fill in with the default value.
1337:             * @param nonNormalizedDefaultVal
1338:             */
1339:            protected final String scanAttDefaultDecl(String elName,
1340:                    String atName, String type, XMLString defaultVal,
1341:                    XMLString nonNormalizedDefaultVal) throws IOException,
1342:                    XNIException {
1343:
1344:                String defaultType = null;
1345:                fString.clear();
1346:                defaultVal.clear();
1347:                if (fEntityScanner.skipString("#REQUIRED")) {
1348:                    defaultType = "#REQUIRED";
1349:                } else if (fEntityScanner.skipString("#IMPLIED")) {
1350:                    defaultType = "#IMPLIED";
1351:                } else {
1352:                    if (fEntityScanner.skipString("#FIXED")) {
1353:                        defaultType = "#FIXED";
1354:                        // spaces
1355:                        if (!skipSeparator(true, !scanningInternalSubset())) {
1356:                            reportFatalError(
1357:                                    "MSG_SPACE_REQUIRED_AFTER_FIXED_IN_DEFAULTDECL",
1358:                                    new Object[] { elName, atName });
1359:                        }
1360:                    }
1361:                    // AttValue 
1362:                    boolean isVC = !fStandalone
1363:                            && (fSeenExternalDTD || fSeenPEReferences);
1364:                    scanAttributeValue(defaultVal, nonNormalizedDefaultVal,
1365:                            atName, isVC, elName);
1366:                }
1367:                return defaultType;
1368:
1369:            } // ScanAttDefaultDecl
1370:
1371:            /**
1372:             * Scans an entity declaration
1373:             * <p>
1374:             * <pre>
1375:             * [70]    EntityDecl  ::=    GEDecl | PEDecl 
1376:             * [71]    GEDecl      ::=    '&lt;!ENTITY' S Name S EntityDef S? '>' 
1377:             * [72]    PEDecl      ::=    '&lt;!ENTITY' S '%' S Name S PEDef S? '>' 
1378:             * [73]    EntityDef   ::=    EntityValue | (ExternalID NDataDecl?) 
1379:             * [74]    PEDef       ::=    EntityValue | ExternalID 
1380:             * [75]    ExternalID  ::=    'SYSTEM' S SystemLiteral 
1381:             *                          | 'PUBLIC' S PubidLiteral S SystemLiteral  
1382:             * [76]    NDataDecl   ::=    S 'NDATA' S Name 
1383:             * </pre>
1384:             * <p>
1385:             * <strong>Note:</strong> Called after scanning past '&lt;!ENTITY'
1386:             */
1387:            private final void scanEntityDecl() throws IOException,
1388:                    XNIException {
1389:
1390:                boolean isPEDecl = false;
1391:                boolean sawPERef = false;
1392:                fReportEntity = false;
1393:                if (fEntityScanner.skipSpaces()) {
1394:                    if (!fEntityScanner.skipChar('%')) {
1395:                        isPEDecl = false; // <!ENTITY x "x">
1396:                    } else if (skipSeparator(true, !scanningInternalSubset())) {
1397:                        // <!ENTITY % x "x">
1398:                        isPEDecl = true;
1399:                    } else if (scanningInternalSubset()) {
1400:                        reportFatalError(
1401:                                "MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL",
1402:                                null);
1403:                        isPEDecl = true;
1404:                    } else if (fEntityScanner.peekChar() == '%') {
1405:                        // <!ENTITY %%x; "x"> is legal
1406:                        skipSeparator(false, !scanningInternalSubset());
1407:                        isPEDecl = true;
1408:                    } else {
1409:                        sawPERef = true;
1410:                    }
1411:                } else if (scanningInternalSubset()
1412:                        || !fEntityScanner.skipChar('%')) {
1413:                    // <!ENTITY[^ ]...> or <!ENTITY[^ %]...>
1414:                    reportFatalError(
1415:                            "MSG_SPACE_REQUIRED_BEFORE_ENTITY_NAME_IN_ENTITYDECL",
1416:                            null);
1417:                    isPEDecl = false;
1418:                } else if (fEntityScanner.skipSpaces()) {
1419:                    // <!ENTITY% ...>
1420:                    reportFatalError(
1421:                            "MSG_SPACE_REQUIRED_BEFORE_PERCENT_IN_PEDECL", null);
1422:                    isPEDecl = false;
1423:                } else {
1424:                    sawPERef = true;
1425:                }
1426:                if (sawPERef) {
1427:                    while (true) {
1428:                        String peName = fEntityScanner.scanName();
1429:                        if (peName == null) {
1430:                            reportFatalError("NameRequiredInPEReference", null);
1431:                        } else if (!fEntityScanner.skipChar(';')) {
1432:                            reportFatalError("SemicolonRequiredInPEReference",
1433:                                    new Object[] { peName });
1434:                        } else {
1435:                            startPE(peName, false);
1436:                        }
1437:                        fEntityScanner.skipSpaces();
1438:                        if (!fEntityScanner.skipChar('%'))
1439:                            break;
1440:                        if (!isPEDecl) {
1441:                            if (skipSeparator(true, !scanningInternalSubset())) {
1442:                                isPEDecl = true;
1443:                                break;
1444:                            }
1445:                            isPEDecl = fEntityScanner.skipChar('%');
1446:                        }
1447:                    }
1448:                }
1449:
1450:                // name
1451:                String name = null;
1452:                if (fNamespaces) {
1453:                    name = fEntityScanner.scanNCName();
1454:                } else {
1455:                    name = fEntityScanner.scanName();
1456:                }
1457:                if (name == null) {
1458:                    reportFatalError("MSG_ENTITY_NAME_REQUIRED_IN_ENTITYDECL",
1459:                            null);
1460:                }
1461:                // spaces
1462:                if (!skipSeparator(true, !scanningInternalSubset())) {
1463:                    if (fNamespaces && fEntityScanner.peekChar() == ':') {
1464:                        fEntityScanner.scanChar();
1465:                        XMLStringBuffer colonName = new XMLStringBuffer(name);
1466:                        colonName.append(":");
1467:                        String str = fEntityScanner.scanName();
1468:                        if (str != null)
1469:                            colonName.append(str);
1470:                        reportFatalError("ColonNotLegalWithNS",
1471:                                new Object[] { colonName.toString() });
1472:                        if (!skipSeparator(true, !scanningInternalSubset())) {
1473:                            reportFatalError(
1474:                                    "MSG_SPACE_REQUIRED_AFTER_ENTITY_NAME_IN_ENTITYDECL",
1475:                                    new Object[] { name });
1476:                        }
1477:                    } else {
1478:                        reportFatalError(
1479:                                "MSG_SPACE_REQUIRED_AFTER_ENTITY_NAME_IN_ENTITYDECL",
1480:                                new Object[] { name });
1481:                    }
1482:                }
1483:
1484:                // external id
1485:                scanExternalID(fStrings, false);
1486:                String systemId = fStrings[0];
1487:                String publicId = fStrings[1];
1488:
1489:                String notation = null;
1490:                // NDATA
1491:                boolean sawSpace = skipSeparator(true,
1492:                        !scanningInternalSubset());
1493:                if (!isPEDecl && fEntityScanner.skipString("NDATA")) {
1494:                    // check whether there was space before NDATA
1495:                    if (!sawSpace) {
1496:                        reportFatalError(
1497:                                "MSG_SPACE_REQUIRED_BEFORE_NDATA_IN_UNPARSED_ENTITYDECL",
1498:                                new Object[] { name });
1499:                    }
1500:
1501:                    // spaces
1502:                    if (!skipSeparator(true, !scanningInternalSubset())) {
1503:                        reportFatalError(
1504:                                "MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_UNPARSED_ENTITYDECL",
1505:                                new Object[] { name });
1506:                    }
1507:                    notation = fEntityScanner.scanName();
1508:                    if (notation == null) {
1509:                        reportFatalError(
1510:                                "MSG_NOTATION_NAME_REQUIRED_FOR_UNPARSED_ENTITYDECL",
1511:                                new Object[] { name });
1512:                    }
1513:                }
1514:
1515:                // internal entity
1516:                if (systemId == null) {
1517:                    scanEntityValue(fLiteral, fLiteral2);
1518:                    // since we need it's value anyway, let's snag it so it doesn't get corrupted 
1519:                    // if a new load takes place before we store the entity values
1520:                    fStringBuffer.clear();
1521:                    fStringBuffer2.clear();
1522:                    fStringBuffer.append(fLiteral.ch, fLiteral.offset,
1523:                            fLiteral.length);
1524:                    fStringBuffer2.append(fLiteral2.ch, fLiteral2.offset,
1525:                            fLiteral2.length);
1526:                }
1527:
1528:                // skip possible trailing space
1529:                skipSeparator(false, !scanningInternalSubset());
1530:
1531:                // end
1532:                if (!fEntityScanner.skipChar('>')) {
1533:                    reportFatalError("EntityDeclUnterminated",
1534:                            new Object[] { name });
1535:                }
1536:                fMarkUpDepth--;
1537:
1538:                // register entity and make callback
1539:                if (isPEDecl) {
1540:                    name = "%" + name;
1541:                }
1542:                if (systemId != null) {
1543:                    String baseSystemId = fEntityScanner.getBaseSystemId();
1544:                    if (notation != null) {
1545:                        fEntityManager.addUnparsedEntity(name, publicId,
1546:                                systemId, baseSystemId, notation);
1547:                    } else {
1548:                        fEntityManager.addExternalEntity(name, publicId,
1549:                                systemId, baseSystemId);
1550:                    }
1551:                    if (fDTDHandler != null) {
1552:                        fResourceIdentifier.setValues(publicId, systemId,
1553:                                baseSystemId, XMLEntityManager.expandSystemId(
1554:                                        systemId, baseSystemId, false));
1555:                        if (notation != null) {
1556:                            fDTDHandler.unparsedEntityDecl(name,
1557:                                    fResourceIdentifier, notation, null);
1558:                        } else {
1559:                            fDTDHandler.externalEntityDecl(name,
1560:                                    fResourceIdentifier, null);
1561:                        }
1562:                    }
1563:                } else {
1564:                    fEntityManager.addInternalEntity(name, fStringBuffer
1565:                            .toString());
1566:                    if (fDTDHandler != null) {
1567:                        fDTDHandler.internalEntityDecl(name, fStringBuffer,
1568:                                fStringBuffer2, null);
1569:                    }
1570:                }
1571:                fReportEntity = true;
1572:
1573:            } // scanEntityDecl()
1574:
1575:            /**
1576:             * Scans an entity value.
1577:             *
1578:             * @param value The string to fill in with the value.
1579:             * @param nonNormalizedValue The string to fill in with the 
1580:             *                           non-normalized value.
1581:             *
1582:             * <strong>Note:</strong> This method uses fString, fStringBuffer (through
1583:             * the use of scanCharReferenceValue), and fStringBuffer2, anything in them
1584:             * at the time of calling is lost.
1585:             */
1586:            protected final void scanEntityValue(XMLString value,
1587:                    XMLString nonNormalizedValue) throws IOException,
1588:                    XNIException {
1589:                int quote = fEntityScanner.scanChar();
1590:                if (quote != '\'' && quote != '"') {
1591:                    reportFatalError("OpenQuoteMissingInDecl", null);
1592:                }
1593:                // store at which depth of entities we start
1594:                int entityDepth = fEntityDepth;
1595:
1596:                XMLString literal = fString;
1597:                XMLString literal2 = fString;
1598:                if (fEntityScanner.scanLiteral(quote, fString) != quote) {
1599:                    fStringBuffer.clear();
1600:                    fStringBuffer2.clear();
1601:                    do {
1602:                        fStringBuffer.append(fString);
1603:                        fStringBuffer2.append(fString);
1604:                        if (fEntityScanner.skipChar('&')) {
1605:                            if (fEntityScanner.skipChar('#')) {
1606:                                fStringBuffer2.append("&#");
1607:                                scanCharReferenceValue(fStringBuffer,
1608:                                        fStringBuffer2);
1609:                            } else {
1610:                                fStringBuffer.append('&');
1611:                                fStringBuffer2.append('&');
1612:                                String eName = fEntityScanner.scanName();
1613:                                if (eName == null) {
1614:                                    reportFatalError("NameRequiredInReference",
1615:                                            null);
1616:                                } else {
1617:                                    fStringBuffer.append(eName);
1618:                                    fStringBuffer2.append(eName);
1619:                                }
1620:                                if (!fEntityScanner.skipChar(';')) {
1621:                                    reportFatalError(
1622:                                            "SemicolonRequiredInReference",
1623:                                            new Object[] { eName });
1624:                                } else {
1625:                                    fStringBuffer.append(';');
1626:                                    fStringBuffer2.append(';');
1627:                                }
1628:                            }
1629:                        } else if (fEntityScanner.skipChar('%')) {
1630:                            while (true) {
1631:                                fStringBuffer2.append('%');
1632:                                String peName = fEntityScanner.scanName();
1633:                                if (peName == null) {
1634:                                    reportFatalError(
1635:                                            "NameRequiredInPEReference", null);
1636:                                } else if (!fEntityScanner.skipChar(';')) {
1637:                                    reportFatalError(
1638:                                            "SemicolonRequiredInPEReference",
1639:                                            new Object[] { peName });
1640:                                } else {
1641:                                    if (scanningInternalSubset()) {
1642:                                        reportFatalError(
1643:                                                "PEReferenceWithinMarkup",
1644:                                                new Object[] { peName });
1645:                                    }
1646:                                    fStringBuffer2.append(peName);
1647:                                    fStringBuffer2.append(';');
1648:                                }
1649:                                startPE(peName, true);
1650:                                // REVISIT: [Q] Why do we skip spaces here? -Ac
1651:                                // REVISIT: This will make returning the non-
1652:                                //          normalized value harder. -Ac
1653:                                fEntityScanner.skipSpaces();
1654:                                if (!fEntityScanner.skipChar('%'))
1655:                                    break;
1656:                            }
1657:                        } else {
1658:                            int c = fEntityScanner.peekChar();
1659:                            if (XMLChar.isHighSurrogate(c)) {
1660:                                scanSurrogates(fStringBuffer2);
1661:                            } else if (isInvalidLiteral(c)) {
1662:                                reportFatalError("InvalidCharInLiteral",
1663:                                        new Object[] { Integer.toHexString(c) });
1664:                                fEntityScanner.scanChar();
1665:                            }
1666:                            // if it's not the delimiting quote or if it is but from a
1667:                            // different entity than the one this literal started from,
1668:                            // simply append the character to our buffer
1669:                            else if (c != quote || entityDepth != fEntityDepth) {
1670:                                fStringBuffer.append((char) c);
1671:                                fStringBuffer2.append((char) c);
1672:                                fEntityScanner.scanChar();
1673:                            }
1674:                        }
1675:                    } while (fEntityScanner.scanLiteral(quote, fString) != quote);
1676:                    fStringBuffer.append(fString);
1677:                    fStringBuffer2.append(fString);
1678:                    literal = fStringBuffer;
1679:                    literal2 = fStringBuffer2;
1680:                }
1681:                value.setValues(literal);
1682:                nonNormalizedValue.setValues(literal2);
1683:                if (!fEntityScanner.skipChar(quote)) {
1684:                    reportFatalError("CloseQuoteMissingInDecl", null);
1685:                }
1686:            } // scanEntityValue(XMLString,XMLString):void
1687:
1688:            /**
1689:             * Scans a notation declaration
1690:             * <p>
1691:             * <pre>
1692:             * [82] NotationDecl ::= '&lt;!NOTATION' S Name S (ExternalID|PublicID) S? '>'
1693:             * [83]  PublicID    ::= 'PUBLIC' S PubidLiteral  
1694:             * </pre>
1695:             * <p>
1696:             * <strong>Note:</strong> Called after scanning past '&lt;!NOTATION'
1697:             */
1698:            private final void scanNotationDecl() throws IOException,
1699:                    XNIException {
1700:
1701:                // spaces
1702:                fReportEntity = false;
1703:                if (!skipSeparator(true, !scanningInternalSubset())) {
1704:                    reportFatalError(
1705:                            "MSG_SPACE_REQUIRED_BEFORE_NOTATION_NAME_IN_NOTATIONDECL",
1706:                            null);
1707:                }
1708:
1709:                // notation name
1710:                String name = null;
1711:                if (fNamespaces) {
1712:                    name = fEntityScanner.scanNCName();
1713:                } else {
1714:                    name = fEntityScanner.scanName();
1715:                }
1716:                if (name == null) {
1717:                    reportFatalError(
1718:                            "MSG_NOTATION_NAME_REQUIRED_IN_NOTATIONDECL", null);
1719:                }
1720:
1721:                // spaces
1722:                if (!skipSeparator(true, !scanningInternalSubset())) {
1723:                    // check for invalid ":"
1724:                    if (fNamespaces && fEntityScanner.peekChar() == ':') {
1725:                        fEntityScanner.scanChar();
1726:                        XMLStringBuffer colonName = new XMLStringBuffer(name);
1727:                        colonName.append(":");
1728:                        colonName.append(fEntityScanner.scanName());
1729:                        reportFatalError("ColonNotLegalWithNS",
1730:                                new Object[] { colonName.toString() });
1731:                        skipSeparator(true, !scanningInternalSubset());
1732:                    } else {
1733:                        reportFatalError(
1734:                                "MSG_SPACE_REQUIRED_AFTER_NOTATION_NAME_IN_NOTATIONDECL",
1735:                                new Object[] { name });
1736:                    }
1737:                }
1738:
1739:                // external id
1740:                scanExternalID(fStrings, true);
1741:                String systemId = fStrings[0];
1742:                String publicId = fStrings[1];
1743:                String baseSystemId = fEntityScanner.getBaseSystemId();
1744:
1745:                if (systemId == null && publicId == null) {
1746:                    reportFatalError("ExternalIDorPublicIDRequired",
1747:                            new Object[] { name });
1748:                }
1749:
1750:                // skip possible trailing space
1751:                skipSeparator(false, !scanningInternalSubset());
1752:
1753:                // end
1754:                if (!fEntityScanner.skipChar('>')) {
1755:                    reportFatalError("NotationDeclUnterminated",
1756:                            new Object[] { name });
1757:                }
1758:                fMarkUpDepth--;
1759:
1760:                // call handler
1761:                if (fDTDHandler != null) {
1762:                    fResourceIdentifier.setValues(publicId, systemId,
1763:                            baseSystemId, XMLEntityManager.expandSystemId(
1764:                                    systemId, baseSystemId, false));
1765:                    fDTDHandler.notationDecl(name, fResourceIdentifier, null);
1766:                }
1767:                fReportEntity = true;
1768:
1769:            } // scanNotationDecl()
1770:
1771:            /**
1772:             * Scans a conditional section. If it's a section to ignore the whole
1773:             * section gets scanned through and this method only returns after the
1774:             * closing bracket has been found. When it's an include section though, it
1775:             * returns to let the main loop take care of scanning it. In that case the
1776:             * end of the section if handled by the main loop (scanDecls).
1777:             * <p>
1778:             * <pre>
1779:             * [61] conditionalSect   ::= includeSect | ignoreSect  
1780:             * [62] includeSect       ::= '&lt;![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>'
1781:             * [63] ignoreSect   ::= '&lt;![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>'
1782:             * [64] ignoreSectContents ::= Ignore ('&lt;![' ignoreSectContents ']]>' Ignore)* 
1783:             * [65] Ignore            ::=    Char* - (Char* ('&lt;![' | ']]>') Char*)  
1784:             * </pre>
1785:             * <p>
1786:             * <strong>Note:</strong> Called after scanning past '&lt;![' */
1787:            private final void scanConditionalSect(int currPEDepth)
1788:                    throws IOException, XNIException {
1789:
1790:                fReportEntity = false;
1791:                skipSeparator(false, !scanningInternalSubset());
1792:
1793:                if (fEntityScanner.skipString("INCLUDE")) {
1794:                    skipSeparator(false, !scanningInternalSubset());
1795:                    if (currPEDepth != fPEDepth && fValidation) {
1796:                        fErrorReporter
1797:                                .reportError(
1798:                                        XMLMessageFormatter.XML_DOMAIN,
1799:                                        "INVALID_PE_IN_CONDITIONAL",
1800:                                        new Object[] { fEntityManager.fCurrentEntity.name },
1801:                                        XMLErrorReporter.SEVERITY_ERROR);
1802:                    }
1803:                    // call handler
1804:                    if (!fEntityScanner.skipChar('[')) {
1805:                        reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
1806:                                null);
1807:                    }
1808:
1809:                    if (fDTDHandler != null) {
1810:                        fDTDHandler.startConditional(
1811:                                XMLDTDHandler.CONDITIONAL_INCLUDE, null);
1812:                    }
1813:                    fIncludeSectDepth++;
1814:                    // just stop there and go back to the main loop
1815:                    fReportEntity = true;
1816:                } else if (fEntityScanner.skipString("IGNORE")) {
1817:                    skipSeparator(false, !scanningInternalSubset());
1818:                    if (currPEDepth != fPEDepth && fValidation) {
1819:                        fErrorReporter
1820:                                .reportError(
1821:                                        XMLMessageFormatter.XML_DOMAIN,
1822:                                        "INVALID_PE_IN_CONDITIONAL",
1823:                                        new Object[] { fEntityManager.fCurrentEntity.name },
1824:                                        XMLErrorReporter.SEVERITY_ERROR);
1825:                    }
1826:                    // call handler
1827:                    if (fDTDHandler != null) {
1828:                        fDTDHandler.startConditional(
1829:                                XMLDTDHandler.CONDITIONAL_IGNORE, null);
1830:                    }
1831:                    if (!fEntityScanner.skipChar('[')) {
1832:                        reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
1833:                                null);
1834:                    }
1835:                    fReportEntity = true;
1836:                    int initialDepth = ++fIncludeSectDepth;
1837:                    if (fDTDHandler != null) {
1838:                        fIgnoreConditionalBuffer.clear();
1839:                    }
1840:                    while (true) {
1841:                        if (fEntityScanner.skipChar('<')) {
1842:                            if (fDTDHandler != null) {
1843:                                fIgnoreConditionalBuffer.append('<');
1844:                            }
1845:                            //
1846:                            // These tests are split so that we handle cases like
1847:                            // '<<![' and '<!<![' which we might otherwise miss.
1848:                            //
1849:                            if (fEntityScanner.skipChar('!')) {
1850:                                if (fEntityScanner.skipChar('[')) {
1851:                                    if (fDTDHandler != null) {
1852:                                        fIgnoreConditionalBuffer.append("![");
1853:                                    }
1854:                                    fIncludeSectDepth++;
1855:                                } else {
1856:                                    if (fDTDHandler != null) {
1857:                                        fIgnoreConditionalBuffer.append("!");
1858:                                    }
1859:                                }
1860:                            }
1861:                        } else if (fEntityScanner.skipChar(']')) {
1862:                            if (fDTDHandler != null) {
1863:                                fIgnoreConditionalBuffer.append(']');
1864:                            }
1865:                            //
1866:                            // The same thing goes for ']<![' and '<]]>', etc.
1867:                            //
1868:                            if (fEntityScanner.skipChar(']')) {
1869:                                if (fDTDHandler != null) {
1870:                                    fIgnoreConditionalBuffer.append(']');
1871:                                }
1872:                                while (fEntityScanner.skipChar(']')) {
1873:                                    /* empty loop body */
1874:                                    if (fDTDHandler != null) {
1875:                                        fIgnoreConditionalBuffer.append(']');
1876:                                    }
1877:                                }
1878:                                if (fEntityScanner.skipChar('>')) {
1879:                                    if (fIncludeSectDepth-- == initialDepth) {
1880:                                        fMarkUpDepth--;
1881:                                        // call handler
1882:                                        if (fDTDHandler != null) {
1883:                                            fLiteral
1884:                                                    .setValues(
1885:                                                            fIgnoreConditionalBuffer.ch,
1886:                                                            0,
1887:                                                            fIgnoreConditionalBuffer.length - 2);
1888:                                            fDTDHandler.ignoredCharacters(
1889:                                                    fLiteral, null);
1890:                                            fDTDHandler.endConditional(null);
1891:                                        }
1892:                                        return;
1893:                                    } else if (fDTDHandler != null) {
1894:                                        fIgnoreConditionalBuffer.append('>');
1895:                                    }
1896:                                }
1897:                            }
1898:                        } else {
1899:                            int c = fEntityScanner.scanChar();
1900:                            if (fScannerState == SCANNER_STATE_END_OF_INPUT) {
1901:                                reportFatalError("IgnoreSectUnterminated", null);
1902:                                return;
1903:                            }
1904:                            if (fDTDHandler != null) {
1905:                                fIgnoreConditionalBuffer.append((char) c);
1906:                            }
1907:                        }
1908:                    }
1909:                } else {
1910:                    reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1911:                }
1912:
1913:            } // scanConditionalSect()
1914:
1915:            /** 
1916:             * Dispatch an XML "event".
1917:             *
1918:             * @param complete True if this method is intended to scan
1919:             *                 and dispatch as much as possible.                 
1920:             *
1921:             * @return True if there is more to scan.
1922:             *
1923:             * @throws IOException  Thrown on i/o error.
1924:             * @throws XNIException Thrown on parse error.
1925:             *
1926:             */
1927:            protected final boolean scanDecls(boolean complete)
1928:                    throws IOException, XNIException {
1929:
1930:                skipSeparator(false, true);
1931:                boolean again = true;
1932:                while (again && fScannerState == SCANNER_STATE_MARKUP_DECL) {
1933:                    again = complete;
1934:                    if (fEntityScanner.skipChar('<')) {
1935:                        fMarkUpDepth++;
1936:                        if (fEntityScanner.skipChar('?')) {
1937:                            scanPI();
1938:                        } else if (fEntityScanner.skipChar('!')) {
1939:                            if (fEntityScanner.skipChar('-')) {
1940:                                if (!fEntityScanner.skipChar('-')) {
1941:                                    reportFatalError(
1942:                                            "MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
1943:                                            null);
1944:                                } else {
1945:                                    scanComment();
1946:                                }
1947:                            } else if (fEntityScanner.skipString("ELEMENT")) {
1948:                                scanElementDecl();
1949:                            } else if (fEntityScanner.skipString("ATTLIST")) {
1950:                                scanAttlistDecl();
1951:                            } else if (fEntityScanner.skipString("ENTITY")) {
1952:                                scanEntityDecl();
1953:                            } else if (fEntityScanner.skipString("NOTATION")) {
1954:                                scanNotationDecl();
1955:                            } else if (fEntityScanner.skipChar('[')
1956:                                    && !scanningInternalSubset()) {
1957:                                scanConditionalSect(fPEDepth);
1958:                            } else {
1959:                                fMarkUpDepth--;
1960:                                reportFatalError(
1961:                                        "MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
1962:                                        null);
1963:                            }
1964:                        } else {
1965:                            fMarkUpDepth--;
1966:                            reportFatalError(
1967:                                    "MSG_MARKUP_NOT_RECOGNIZED_IN_DTD", null);
1968:                        }
1969:                    } else if (fIncludeSectDepth > 0
1970:                            && fEntityScanner.skipChar(']')) {
1971:                        // end of conditional section?
1972:                        if (!fEntityScanner.skipChar(']')
1973:                                || !fEntityScanner.skipChar('>')) {
1974:                            reportFatalError("IncludeSectUnterminated", null);
1975:                        }
1976:                        // call handler
1977:                        if (fDTDHandler != null) {
1978:                            fDTDHandler.endConditional(null);
1979:                        }
1980:                        // decreaseMarkupDepth();
1981:                        fIncludeSectDepth--;
1982:                        fMarkUpDepth--;
1983:                    } else if (scanningInternalSubset()
1984:                            && fEntityScanner.peekChar() == ']') {
1985:                        // this is the end of the internal subset, let's stop here
1986:                        return false;
1987:                    } else if (fEntityScanner.skipSpaces()) {
1988:                        // simply skip
1989:                    } else {
1990:                        reportFatalError("MSG_MARKUP_NOT_RECOGNIZED_IN_DTD",
1991:                                null);
1992:                        // Skip the part in error
1993:                        int ch;
1994:                        do {
1995:                            // Ignore the current character
1996:                            fEntityScanner.scanChar();
1997:                            // Skip any separators
1998:                            skipSeparator(false, true);
1999:                            // Keeping getting the next character,
2000:                            // until it's one of the expected ones
2001:                            ch = fEntityScanner.peekChar();
2002:                        } while (ch != '<' && ch != ']' && !XMLChar.isSpace(ch));
2003:                    }
2004:                    skipSeparator(false, true);
2005:                }
2006:                return fScannerState != SCANNER_STATE_END_OF_INPUT;
2007:            }
2008:
2009:            /**
2010:             * Skip separator. This is typically just whitespace but it can also be one
2011:             * or more parameter entity references.
2012:             * <p>
2013:             * If there are some it "expands them" by calling the corresponding entity
2014:             * from the entity manager.
2015:             * <p>
2016:             * This is recursive and will process has many refs as possible.
2017:             *
2018:             * @param spaceRequired Specify whether some leading whitespace should be
2019:             *                      found
2020:             * @param lookForPERefs Specify whether parameter entity references should
2021:             *                      be looked for
2022:             * @return True if any leading whitespace was found or the end of a
2023:             *         parameter entity was crossed.
2024:             */
2025:            private boolean skipSeparator(boolean spaceRequired,
2026:                    boolean lookForPERefs) throws IOException, XNIException {
2027:                int depth = fPEDepth;
2028:                boolean sawSpace = fEntityScanner.skipSpaces();
2029:                if (!lookForPERefs || !fEntityScanner.skipChar('%')) {
2030:                    return !spaceRequired || sawSpace || (depth != fPEDepth);
2031:                }
2032:                while (true) {
2033:                    String name = fEntityScanner.scanName();
2034:                    if (name == null) {
2035:                        reportFatalError("NameRequiredInPEReference", null);
2036:                    } else if (!fEntityScanner.skipChar(';')) {
2037:                        reportFatalError("SemicolonRequiredInPEReference",
2038:                                new Object[] { name });
2039:                    }
2040:                    startPE(name, false);
2041:                    fEntityScanner.skipSpaces();
2042:                    if (!fEntityScanner.skipChar('%'))
2043:                        return true;
2044:                }
2045:            }
2046:
2047:            /*
2048:             * Element Children Content Stack
2049:             */
2050:            private final void pushContentStack(int c) {
2051:                if (fContentStack.length == fContentDepth) {
2052:                    int[] newStack = new int[fContentDepth * 2];
2053:                    System.arraycopy(fContentStack, 0, newStack, 0,
2054:                            fContentDepth);
2055:                    fContentStack = newStack;
2056:                }
2057:                fContentStack[fContentDepth++] = c;
2058:            }
2059:
2060:            private final int popContentStack() {
2061:                return fContentStack[--fContentDepth];
2062:            }
2063:
2064:            /*
2065:             * Parameter Entity Stack
2066:             */
2067:            private final void pushPEStack(int depth, boolean report) {
2068:                if (fPEStack.length == fPEDepth) {
2069:                    int[] newIntStack = new int[fPEDepth * 2];
2070:                    System.arraycopy(fPEStack, 0, newIntStack, 0, fPEDepth);
2071:                    fPEStack = newIntStack;
2072:                    // report end/start calls
2073:                    boolean[] newBooleanStack = new boolean[fPEDepth * 2];
2074:                    System
2075:                            .arraycopy(fPEReport, 0, newBooleanStack, 0,
2076:                                    fPEDepth);
2077:                    fPEReport = newBooleanStack;
2078:
2079:                }
2080:                fPEReport[fPEDepth] = report;
2081:                fPEStack[fPEDepth++] = depth;
2082:            }
2083:
2084:            /** pop the stack */
2085:            private final int popPEStack() {
2086:                return fPEStack[--fPEDepth];
2087:            }
2088:
2089:            /** look at the top of the stack */
2090:            private final boolean peekReportEntity() {
2091:                return fPEReport[fPEDepth - 1];
2092:            }
2093:
2094:            /*
2095:             * Utility method
2096:             */
2097:            private final void ensureEnumerationSize(int size) {
2098:                if (fEnumeration.length == size) {
2099:                    String[] newEnum = new String[size * 2];
2100:                    System.arraycopy(fEnumeration, 0, newEnum, 0, size);
2101:                    fEnumeration = newEnum;
2102:                }
2103:            }
2104:
2105:            // private methods
2106:            private void init() {
2107:                // reset state related data
2108:                fStartDTDCalled = false;
2109:                fExtEntityDepth = 0;
2110:                fIncludeSectDepth = 0;
2111:                fMarkUpDepth = 0;
2112:                fPEDepth = 0;
2113:
2114:                fStandalone = false;
2115:                fSeenExternalDTD = false;
2116:                fSeenPEReferences = false;
2117:
2118:                // set starting state
2119:                setScannerState(SCANNER_STATE_TEXT_DECL);
2120:            }
2121:
2122:            private int skipInvalidEnumerationValue() throws IOException {
2123:                int c;
2124:                do {
2125:                    c = fEntityScanner.scanChar();
2126:                } while (c != '|' && c != ')');
2127:                ensureEnumerationSize(fEnumerationCount + 1);
2128:                fEnumeration[fEnumerationCount++] = XMLSymbols.EMPTY_STRING;
2129:                return c;
2130:            }
2131:
2132:        } // class XMLDTDScannerImpl
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.