Source Code Cross Referenced for ToStream.java in  » XML » xalan » org » apache » xml » serializer » 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 » xalan » org.apache.xml.serializer 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright 2001-2004 The Apache Software Foundation.
0003:         *
0004:         * Licensed under the Apache License, Version 2.0 (the "License");
0005:         * you may not use this file except in compliance with the License.
0006:         * You may obtain a copy of the License at
0007:         *
0008:         *     http://www.apache.org/licenses/LICENSE-2.0
0009:         *
0010:         * Unless required by applicable law or agreed to in writing, software
0011:         * distributed under the License is distributed on an "AS IS" BASIS,
0012:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013:         * See the License for the specific language governing permissions and
0014:         * limitations under the License.
0015:         */
0016:        /*
0017:         * $Id: ToStream.java,v 1.45 2005/08/04 23:57:06 minchau Exp $
0018:         */
0019:        package org.apache.xml.serializer;
0020:
0021:        import java.io.IOException;
0022:        import java.io.OutputStream;
0023:        import java.io.UnsupportedEncodingException;
0024:        import java.io.Writer;
0025:        import java.util.Properties;
0026:        import java.util.StringTokenizer;
0027:        import java.util.Vector;
0028:
0029:        import javax.xml.transform.ErrorListener;
0030:        import javax.xml.transform.OutputKeys;
0031:        import javax.xml.transform.Transformer;
0032:        import javax.xml.transform.TransformerException;
0033:
0034:        import org.apache.xml.serializer.utils.MsgKey;
0035:        import org.apache.xml.serializer.utils.Utils;
0036:        import org.apache.xml.serializer.utils.WrappedRuntimeException;
0037:        import org.w3c.dom.Node;
0038:        import org.xml.sax.Attributes;
0039:        import org.xml.sax.ContentHandler;
0040:        import org.xml.sax.SAXException;
0041:
0042:        //import com.sun.media.sound.IESecurity;
0043:
0044:        /**
0045:         * This abstract class is a base class for other stream 
0046:         * serializers (xml, html, text ...) that write output to a stream.
0047:         * 
0048:         * @xsl.usage internal
0049:         */
0050:        abstract public class ToStream extends SerializerBase {
0051:
0052:            private static final String COMMENT_BEGIN = "<!--";
0053:            private static final String COMMENT_END = "-->";
0054:
0055:            /** Stack to keep track of disabling output escaping. */
0056:            protected BoolStack m_disableOutputEscapingStates = new BoolStack();
0057:
0058:            /**
0059:             * The encoding information associated with this serializer.
0060:             * Although initially there is no encoding,
0061:             * there is a dummy EncodingInfo object that will say
0062:             * that every character is in the encoding. This is useful
0063:             * for a serializer that is in temporary output state and has
0064:             * no associated encoding. A serializer in final output state
0065:             * will have an encoding, and will worry about whether 
0066:             * single chars or surrogate pairs of high/low chars form
0067:             * characters in the output encoding. 
0068:             */
0069:            EncodingInfo m_encodingInfo = new EncodingInfo(null, null);
0070:
0071:            /**
0072:             * Stack to keep track of whether or not we need to
0073:             * preserve whitespace.
0074:             * 
0075:             * Used to push/pop values used for the field m_ispreserve, but
0076:             * m_ispreserve is only relevant if m_doIndent is true.
0077:             * If m_doIndent is false this field has no impact.
0078:             * 
0079:             */
0080:            protected BoolStack m_preserves = new BoolStack();
0081:
0082:            /**
0083:             * State flag to tell if preservation of whitespace
0084:             * is important. 
0085:             * 
0086:             * Used only in shouldIndent() but only if m_doIndent is true.
0087:             * If m_doIndent is false this flag has no impact.
0088:             * 
0089:             */
0090:            protected boolean m_ispreserve = false;
0091:
0092:            /**
0093:             * State flag that tells if the previous node processed
0094:             * was text, so we can tell if we should preserve whitespace.
0095:             * 
0096:             * Used in endDocument() and shouldIndent() but
0097:             * only if m_doIndent is true. 
0098:             * If m_doIndent is false this flag has no impact.
0099:             */
0100:            protected boolean m_isprevtext = false;
0101:
0102:            /**
0103:             * The system line separator for writing out line breaks.
0104:             * The default value is from the system property,
0105:             * but this value can be set through the xsl:output
0106:             * extension attribute xalan:line-separator.
0107:             */
0108:            protected char[] m_lineSep = System.getProperty("line.separator")
0109:                    .toCharArray();
0110:
0111:            /**
0112:             * True if the the system line separator is to be used.
0113:             */
0114:            protected boolean m_lineSepUse = true;
0115:
0116:            /**
0117:             * The length of the line seperator, since the write is done
0118:             * one character at a time.
0119:             */
0120:            protected int m_lineSepLen = m_lineSep.length;
0121:
0122:            /**
0123:             * Map that tells which characters should have special treatment, and it
0124:             *  provides character to entity name lookup.
0125:             */
0126:            protected CharInfo m_charInfo;
0127:
0128:            /** True if we control the buffer, and we should flush the output on endDocument. */
0129:            boolean m_shouldFlush = true;
0130:
0131:            /**
0132:             * Add space before '/>' for XHTML.
0133:             */
0134:            protected boolean m_spaceBeforeClose = false;
0135:
0136:            /**
0137:             * Flag to signal that a newline should be added.
0138:             * 
0139:             * Used only in indent() which is called only if m_doIndent is true.
0140:             * If m_doIndent is false this flag has no impact.
0141:             */
0142:            boolean m_startNewLine;
0143:
0144:            /**
0145:             * Tells if we're in an internal document type subset.
0146:             */
0147:            protected boolean m_inDoctype = false;
0148:
0149:            /**
0150:             * Flag to quickly tell if the encoding is UTF8.
0151:             */
0152:            boolean m_isUTF8 = false;
0153:
0154:            /** The xsl:output properties. */
0155:            protected Properties m_format;
0156:
0157:            /**
0158:             * remembers if we are in between the startCDATA() and endCDATA() callbacks
0159:             */
0160:            protected boolean m_cdataStartCalled = false;
0161:
0162:            /**
0163:             * If this flag is true DTD entity references are not left as-is,
0164:             * which is exiting older behavior.
0165:             */
0166:            private boolean m_expandDTDEntities = true;
0167:
0168:            /**
0169:             * Default constructor
0170:             */
0171:            public ToStream() {
0172:            }
0173:
0174:            /**
0175:             * This helper method to writes out "]]>" when closing a CDATA section.
0176:             *
0177:             * @throws org.xml.sax.SAXException
0178:             */
0179:            protected void closeCDATA() throws org.xml.sax.SAXException {
0180:                try {
0181:                    m_writer.write(CDATA_DELIMITER_CLOSE);
0182:                    // write out a CDATA section closing "]]>"
0183:                    m_cdataTagOpen = false; // Remember that we have done so.
0184:                } catch (IOException e) {
0185:                    throw new SAXException(e);
0186:                }
0187:            }
0188:
0189:            /**
0190:             * Serializes the DOM node. Throws an exception only if an I/O
0191:             * exception occured while serializing.
0192:             *
0193:             * @param node Node to serialize.
0194:             * @throws IOException An I/O exception occured while serializing
0195:             */
0196:            public void serialize(Node node) throws IOException {
0197:
0198:                try {
0199:                    TreeWalker walker = new TreeWalker(this );
0200:
0201:                    walker.traverse(node);
0202:                } catch (org.xml.sax.SAXException se) {
0203:                    throw new WrappedRuntimeException(se);
0204:                }
0205:            }
0206:
0207:            /**
0208:             * Taken from XSLTC 
0209:             */
0210:            private boolean m_escaping = true;
0211:
0212:            /**
0213:             * Flush the formatter's result stream.
0214:             *
0215:             * @throws org.xml.sax.SAXException
0216:             */
0217:            protected final void flushWriter() throws org.xml.sax.SAXException {
0218:                final java.io.Writer writer = m_writer;
0219:                if (null != writer) {
0220:                    try {
0221:                        if (writer instanceof  WriterToUTF8Buffered) {
0222:                            if (m_shouldFlush)
0223:                                ((WriterToUTF8Buffered) writer).flush();
0224:                            else
0225:                                ((WriterToUTF8Buffered) writer).flushBuffer();
0226:                        }
0227:                        if (writer instanceof  WriterToASCI) {
0228:                            if (m_shouldFlush)
0229:                                writer.flush();
0230:                        } else {
0231:                            // Flush always. 
0232:                            // Not a great thing if the writer was created 
0233:                            // by this class, but don't have a choice.
0234:                            writer.flush();
0235:                        }
0236:                    } catch (IOException ioe) {
0237:                        throw new org.xml.sax.SAXException(ioe);
0238:                    }
0239:                }
0240:            }
0241:
0242:            /**
0243:             * Get the output stream where the events will be serialized to.
0244:             *
0245:             * @return reference to the result stream, or null of only a writer was
0246:             * set.
0247:             */
0248:            public OutputStream getOutputStream() {
0249:
0250:                if (m_writer instanceof  WriterToUTF8Buffered)
0251:                    return ((WriterToUTF8Buffered) m_writer).getOutputStream();
0252:                if (m_writer instanceof  WriterToASCI)
0253:                    return ((WriterToASCI) m_writer).getOutputStream();
0254:                else
0255:                    return null;
0256:            }
0257:
0258:            // Implement DeclHandler
0259:
0260:            /**
0261:             *   Report an element type declaration.
0262:             *  
0263:             *   <p>The content model will consist of the string "EMPTY", the
0264:             *   string "ANY", or a parenthesised group, optionally followed
0265:             *   by an occurrence indicator.  The model will be normalized so
0266:             *   that all whitespace is removed,and will include the enclosing
0267:             *   parentheses.</p>
0268:             *  
0269:             *   @param name The element type name.
0270:             *   @param model The content model as a normalized string.
0271:             *   @exception SAXException The application may raise an exception.
0272:             */
0273:            public void elementDecl(String name, String model)
0274:                    throws SAXException {
0275:                // Do not inline external DTD
0276:                if (m_inExternalDTD)
0277:                    return;
0278:                try {
0279:                    final java.io.Writer writer = m_writer;
0280:                    DTDprolog();
0281:
0282:                    writer.write("<!ELEMENT ");
0283:                    writer.write(name);
0284:                    writer.write(' ');
0285:                    writer.write(model);
0286:                    writer.write('>');
0287:                    writer.write(m_lineSep, 0, m_lineSepLen);
0288:                } catch (IOException e) {
0289:                    throw new SAXException(e);
0290:                }
0291:
0292:            }
0293:
0294:            /**
0295:             * Report an internal entity declaration.
0296:             *
0297:             * <p>Only the effective (first) declaration for each entity
0298:             * will be reported.</p>
0299:             *
0300:             * @param name The name of the entity.  If it is a parameter
0301:             *        entity, the name will begin with '%'.
0302:             * @param value The replacement text of the entity.
0303:             * @exception SAXException The application may raise an exception.
0304:             * @see #externalEntityDecl
0305:             * @see org.xml.sax.DTDHandler#unparsedEntityDecl
0306:             */
0307:            public void internalEntityDecl(String name, String value)
0308:                    throws SAXException {
0309:                // Do not inline external DTD
0310:                if (m_inExternalDTD)
0311:                    return;
0312:                try {
0313:                    DTDprolog();
0314:                    outputEntityDecl(name, value);
0315:                } catch (IOException e) {
0316:                    throw new SAXException(e);
0317:                }
0318:
0319:            }
0320:
0321:            /**
0322:             * Output the doc type declaration.
0323:             *
0324:             * @param name non-null reference to document type name.
0325:             * NEEDSDOC @param value
0326:             *
0327:             * @throws org.xml.sax.SAXException
0328:             */
0329:            void outputEntityDecl(String name, String value) throws IOException {
0330:                final java.io.Writer writer = m_writer;
0331:                writer.write("<!ENTITY ");
0332:                writer.write(name);
0333:                writer.write(" \"");
0334:                writer.write(value);
0335:                writer.write("\">");
0336:                writer.write(m_lineSep, 0, m_lineSepLen);
0337:            }
0338:
0339:            /**
0340:             * Output a system-dependent line break.
0341:             *
0342:             * @throws org.xml.sax.SAXException
0343:             */
0344:            protected final void outputLineSep() throws IOException {
0345:
0346:                m_writer.write(m_lineSep, 0, m_lineSepLen);
0347:            }
0348:
0349:            /**
0350:             * Specifies an output format for this serializer. It the
0351:             * serializer has already been associated with an output format,
0352:             * it will switch to the new format. This method should not be
0353:             * called while the serializer is in the process of serializing
0354:             * a document.
0355:             *
0356:             * @param format The output format to use
0357:             */
0358:            public void setOutputFormat(Properties format) {
0359:
0360:                boolean shouldFlush = m_shouldFlush;
0361:
0362:                init(m_writer, format, false, false);
0363:
0364:                m_shouldFlush = shouldFlush;
0365:            }
0366:
0367:            /**
0368:             * Initialize the serializer with the specified writer and output format.
0369:             * Must be called before calling any of the serialize methods.
0370:             * This method can be called multiple times and the xsl:output properties
0371:             * passed in the 'format' parameter are accumulated across calls.
0372:             *
0373:             * @param writer The writer to use
0374:             * @param format The output format
0375:             * @param shouldFlush True if the writer should be flushed at EndDocument.
0376:             */
0377:            private synchronized void init(Writer writer, Properties format,
0378:                    boolean defaultProperties, boolean shouldFlush) {
0379:
0380:                m_shouldFlush = shouldFlush;
0381:
0382:                // if we are tracing events we need to trace what
0383:                // characters are written to the output writer.
0384:                if (m_tracer != null
0385:                        && !(writer instanceof  SerializerTraceWriter))
0386:                    m_writer = new SerializerTraceWriter(writer, m_tracer);
0387:                else
0388:                    m_writer = writer;
0389:
0390:                m_format = format;
0391:                //        m_cdataSectionNames =
0392:                //            OutputProperties.getQNameProperties(
0393:                //                OutputKeys.CDATA_SECTION_ELEMENTS,
0394:                //                format);
0395:                setCdataSectionElements(OutputKeys.CDATA_SECTION_ELEMENTS,
0396:                        format);
0397:
0398:                setIndentAmount(OutputPropertyUtils.getIntProperty(
0399:                        OutputPropertiesFactory.S_KEY_INDENT_AMOUNT, format));
0400:                setIndent(OutputPropertyUtils.getBooleanProperty(
0401:                        OutputKeys.INDENT, format));
0402:
0403:                {
0404:                    String sep = format
0405:                            .getProperty(OutputPropertiesFactory.S_KEY_LINE_SEPARATOR);
0406:                    if (sep != null) {
0407:                        m_lineSep = sep.toCharArray();
0408:                        m_lineSepLen = sep.length();
0409:                    }
0410:                }
0411:
0412:                boolean shouldNotWriteXMLHeader = OutputPropertyUtils
0413:                        .getBooleanProperty(OutputKeys.OMIT_XML_DECLARATION,
0414:                                format);
0415:                setOmitXMLDeclaration(shouldNotWriteXMLHeader);
0416:                setDoctypeSystem(format.getProperty(OutputKeys.DOCTYPE_SYSTEM));
0417:                String doctypePublic = format
0418:                        .getProperty(OutputKeys.DOCTYPE_PUBLIC);
0419:                setDoctypePublic(doctypePublic);
0420:
0421:                // if standalone was explicitly specified
0422:                if (format.get(OutputKeys.STANDALONE) != null) {
0423:                    String val = format.getProperty(OutputKeys.STANDALONE);
0424:                    if (defaultProperties)
0425:                        setStandaloneInternal(val);
0426:                    else
0427:                        setStandalone(val);
0428:                }
0429:
0430:                setMediaType(format.getProperty(OutputKeys.MEDIA_TYPE));
0431:
0432:                if (null != doctypePublic) {
0433:                    if (doctypePublic.startsWith("-//W3C//DTD XHTML"))
0434:                        m_spaceBeforeClose = true;
0435:                }
0436:
0437:                /* 
0438:                 * This code is added for XML 1.1 Version output.
0439:                 */
0440:                String version = getVersion();
0441:                if (null == version) {
0442:                    version = format.getProperty(OutputKeys.VERSION);
0443:                    setVersion(version);
0444:                }
0445:
0446:                // initCharsMap();
0447:                String encoding = getEncoding();
0448:                if (null == encoding) {
0449:                    encoding = Encodings.getMimeEncoding(format
0450:                            .getProperty(OutputKeys.ENCODING));
0451:                    setEncoding(encoding);
0452:                }
0453:
0454:                m_isUTF8 = encoding.equals(Encodings.DEFAULT_MIME_ENCODING);
0455:
0456:                // Access this only from the Hashtable level... we don't want to 
0457:                // get default properties.
0458:                String entitiesFileName = (String) format
0459:                        .get(OutputPropertiesFactory.S_KEY_ENTITIES);
0460:
0461:                if (null != entitiesFileName) {
0462:
0463:                    String method = (String) format.get(OutputKeys.METHOD);
0464:
0465:                    m_charInfo = CharInfo.getCharInfo(entitiesFileName, method);
0466:                }
0467:
0468:            }
0469:
0470:            /**
0471:             * Initialize the serializer with the specified writer and output format.
0472:             * Must be called before calling any of the serialize methods.
0473:             *
0474:             * @param writer The writer to use
0475:             * @param format The output format
0476:             */
0477:            private synchronized void init(Writer writer, Properties format) {
0478:                init(writer, format, false, false);
0479:            }
0480:
0481:            /**
0482:             * Initialize the serializer with the specified output stream and output
0483:             * format. Must be called before calling any of the serialize methods.
0484:             *
0485:             * @param output The output stream to use
0486:             * @param format The output format
0487:             * @param defaultProperties true if the properties are the default
0488:             * properties
0489:             * 
0490:             * @throws UnsupportedEncodingException The encoding specified   in the
0491:             * output format is not supported
0492:             */
0493:            protected synchronized void init(OutputStream output,
0494:                    Properties format, boolean defaultProperties)
0495:                    throws UnsupportedEncodingException {
0496:
0497:                String encoding = getEncoding();
0498:                if (encoding == null) {
0499:                    // if not already set then get it from the properties
0500:                    encoding = Encodings.getMimeEncoding(format
0501:                            .getProperty(OutputKeys.ENCODING));
0502:                    setEncoding(encoding);
0503:                }
0504:
0505:                if (encoding.equalsIgnoreCase("UTF-8")) {
0506:                    m_isUTF8 = true;
0507:                    //            if (output instanceof java.io.BufferedOutputStream)
0508:                    //            {
0509:                    //                init(new WriterToUTF8(output), format, defaultProperties, true);
0510:                    //            }
0511:                    //            else if (output instanceof java.io.FileOutputStream)
0512:                    //            {
0513:                    //                init(new WriterToUTF8Buffered(output), format, defaultProperties, true);
0514:                    //            }
0515:                    //            else
0516:                    //            {
0517:                    //                // Not sure what to do in this case.  I'm going to be conservative 
0518:                    //                // and not buffer.
0519:                    //                init(new WriterToUTF8(output), format, defaultProperties, true);
0520:                    //            }
0521:
0522:                    init(new WriterToUTF8Buffered(output), format,
0523:                            defaultProperties, true);
0524:
0525:                } else if (encoding.equals("WINDOWS-1250")
0526:                        || encoding.equals("US-ASCII")
0527:                        || encoding.equals("ASCII")) {
0528:                    init(new WriterToASCI(output), format, defaultProperties,
0529:                            true);
0530:                } else {
0531:                    Writer osw;
0532:
0533:                    try {
0534:                        osw = Encodings.getWriter(output, encoding);
0535:                    } catch (UnsupportedEncodingException uee) {
0536:                        System.out.println("Warning: encoding \"" + encoding
0537:                                + "\" not supported" + ", using "
0538:                                + Encodings.DEFAULT_MIME_ENCODING);
0539:
0540:                        encoding = Encodings.DEFAULT_MIME_ENCODING;
0541:                        setEncoding(encoding);
0542:                        osw = Encodings.getWriter(output, encoding);
0543:                    }
0544:
0545:                    init(osw, format, defaultProperties, true);
0546:                }
0547:
0548:            }
0549:
0550:            /**
0551:             * Returns the output format for this serializer.
0552:             *
0553:             * @return The output format in use
0554:             */
0555:            public Properties getOutputFormat() {
0556:                return m_format;
0557:            }
0558:
0559:            /**
0560:             * Specifies a writer to which the document should be serialized.
0561:             * This method should not be called while the serializer is in
0562:             * the process of serializing a document.
0563:             *
0564:             * @param writer The output writer stream
0565:             */
0566:            public void setWriter(Writer writer) {
0567:                // if we are tracing events we need to trace what 
0568:                // characters are written to the output writer.
0569:                if (m_tracer != null
0570:                        && !(writer instanceof  SerializerTraceWriter))
0571:                    m_writer = new SerializerTraceWriter(writer, m_tracer);
0572:                else
0573:                    m_writer = writer;
0574:            }
0575:
0576:            /**
0577:             * Set if the operating systems end-of-line line separator should
0578:             * be used when serializing.  If set false NL character 
0579:             * (decimal 10) is left alone, otherwise the new-line will be replaced on
0580:             * output with the systems line separator. For example on UNIX this is
0581:             * NL, while on Windows it is two characters, CR NL, where CR is the
0582:             * carriage-return (decimal 13).
0583:             *  
0584:             * @param use_sytem_line_break True if an input NL is replaced with the 
0585:             * operating systems end-of-line separator.
0586:             * @return The previously set value of the serializer.
0587:             */
0588:            public boolean setLineSepUse(boolean use_sytem_line_break) {
0589:                boolean oldValue = m_lineSepUse;
0590:                m_lineSepUse = use_sytem_line_break;
0591:                return oldValue;
0592:            }
0593:
0594:            /**
0595:             * Specifies an output stream to which the document should be
0596:             * serialized. This method should not be called while the
0597:             * serializer is in the process of serializing a document.
0598:             * <p>
0599:             * The encoding specified in the output properties is used, or
0600:             * if no encoding was specified, the default for the selected
0601:             * output method.
0602:             *
0603:             * @param output The output stream
0604:             */
0605:            public void setOutputStream(OutputStream output) {
0606:
0607:                try {
0608:                    Properties format;
0609:                    if (null == m_format)
0610:                        format = OutputPropertiesFactory
0611:                                .getDefaultMethodProperties(Method.XML);
0612:                    else
0613:                        format = m_format;
0614:                    init(output, format, true);
0615:                } catch (UnsupportedEncodingException uee) {
0616:
0617:                    // Should have been warned in init, I guess...
0618:                }
0619:            }
0620:
0621:            /**
0622:             * @see SerializationHandler#setEscaping(boolean)
0623:             */
0624:            public boolean setEscaping(boolean escape) {
0625:                final boolean temp = m_escaping;
0626:                m_escaping = escape;
0627:                return temp;
0628:
0629:            }
0630:
0631:            /**
0632:             * Might print a newline character and the indentation amount
0633:             * of the given depth.
0634:             * 
0635:             * @param depth the indentation depth (element nesting depth)
0636:             *
0637:             * @throws org.xml.sax.SAXException if an error occurs during writing.
0638:             */
0639:            protected void indent(int depth) throws IOException {
0640:
0641:                if (m_startNewLine)
0642:                    outputLineSep();
0643:                /* For m_indentAmount > 0 this extra test might be slower
0644:                 * but Xalan's default value is 0, so this extra test
0645:                 * will run faster in that situation.
0646:                 */
0647:                if (m_indentAmount > 0)
0648:                    printSpace(depth * m_indentAmount);
0649:
0650:            }
0651:
0652:            /**
0653:             * Indent at the current element nesting depth.
0654:             * @throws IOException
0655:             */
0656:            protected void indent() throws IOException {
0657:                indent(m_elemContext.m_currentElemDepth);
0658:            }
0659:
0660:            /**
0661:             * Prints <var>n</var> spaces.
0662:             * @param n         Number of spaces to print.
0663:             *
0664:             * @throws org.xml.sax.SAXException if an error occurs when writing.
0665:             */
0666:            private void printSpace(int n) throws IOException {
0667:                final java.io.Writer writer = m_writer;
0668:                for (int i = 0; i < n; i++) {
0669:                    writer.write(' ');
0670:                }
0671:
0672:            }
0673:
0674:            /**
0675:             * Report an attribute type declaration.
0676:             *
0677:             * <p>Only the effective (first) declaration for an attribute will
0678:             * be reported.  The type will be one of the strings "CDATA",
0679:             * "ID", "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY",
0680:             * "ENTITIES", or "NOTATION", or a parenthesized token group with
0681:             * the separator "|" and all whitespace removed.</p>
0682:             *
0683:             * @param eName The name of the associated element.
0684:             * @param aName The name of the attribute.
0685:             * @param type A string representing the attribute type.
0686:             * @param valueDefault A string representing the attribute default
0687:             *        ("#IMPLIED", "#REQUIRED", or "#FIXED") or null if
0688:             *        none of these applies.
0689:             * @param value A string representing the attribute's default value,
0690:             *        or null if there is none.
0691:             * @exception SAXException The application may raise an exception.
0692:             */
0693:            public void attributeDecl(String eName, String aName, String type,
0694:                    String valueDefault, String value) throws SAXException {
0695:                // Do not inline external DTD
0696:                if (m_inExternalDTD)
0697:                    return;
0698:                try {
0699:                    final java.io.Writer writer = m_writer;
0700:                    DTDprolog();
0701:
0702:                    writer.write("<!ATTLIST ");
0703:                    writer.write(eName);
0704:                    writer.write(' ');
0705:
0706:                    writer.write(aName);
0707:                    writer.write(' ');
0708:                    writer.write(type);
0709:                    if (valueDefault != null) {
0710:                        writer.write(' ');
0711:                        writer.write(valueDefault);
0712:                    }
0713:
0714:                    //writer.write(" ");
0715:                    //writer.write(value);
0716:                    writer.write('>');
0717:                    writer.write(m_lineSep, 0, m_lineSepLen);
0718:                } catch (IOException e) {
0719:                    throw new SAXException(e);
0720:                }
0721:            }
0722:
0723:            /**
0724:             * Get the character stream where the events will be serialized to.
0725:             *
0726:             * @return Reference to the result Writer, or null.
0727:             */
0728:            public Writer getWriter() {
0729:                return m_writer;
0730:            }
0731:
0732:            /**
0733:             * Report a parsed external entity declaration.
0734:             *
0735:             * <p>Only the effective (first) declaration for each entity
0736:             * will be reported.</p>
0737:             *
0738:             * @param name The name of the entity.  If it is a parameter
0739:             *        entity, the name will begin with '%'.
0740:             * @param publicId The declared public identifier of the entity, or
0741:             *        null if none was declared.
0742:             * @param systemId The declared system identifier of the entity.
0743:             * @exception SAXException The application may raise an exception.
0744:             * @see #internalEntityDecl
0745:             * @see org.xml.sax.DTDHandler#unparsedEntityDecl
0746:             */
0747:            public void externalEntityDecl(String name, String publicId,
0748:                    String systemId) throws SAXException {
0749:                try {
0750:                    DTDprolog();
0751:
0752:                    m_writer.write("<!ENTITY ");
0753:                    m_writer.write(name);
0754:                    if (publicId != null) {
0755:                        m_writer.write(" PUBLIC \"");
0756:                        m_writer.write(publicId);
0757:
0758:                    } else {
0759:                        m_writer.write(" SYSTEM \"");
0760:                        m_writer.write(systemId);
0761:                    }
0762:                    m_writer.write("\" >");
0763:                    m_writer.write(m_lineSep, 0, m_lineSepLen);
0764:                } catch (IOException e) {
0765:                    // TODO Auto-generated catch block
0766:                    e.printStackTrace();
0767:                }
0768:
0769:            }
0770:
0771:            /**
0772:             * Tell if this character can be written without escaping.
0773:             */
0774:            protected boolean escapingNotNeeded(char ch) {
0775:                final boolean ret;
0776:                if (ch < 127) {
0777:                    // This is the old/fast code here, but is this 
0778:                    // correct for all encodings?
0779:                    if (ch >= 0x20 || (0x0A == ch || 0x0D == ch || 0x09 == ch))
0780:                        ret = true;
0781:                    else
0782:                        ret = false;
0783:                } else {
0784:                    ret = m_encodingInfo.isInEncoding(ch);
0785:                }
0786:                return ret;
0787:            }
0788:
0789:            /**
0790:             * Once a surrogate has been detected, write out the pair of
0791:             * characters if it is in the encoding, or if there is no
0792:             * encoding, otherwise write out an entity reference
0793:             * of the value of the unicode code point of the character
0794:             * represented by the high/low surrogate pair.
0795:             * <p>
0796:             * An exception is thrown if there is no low surrogate in the pair,
0797:             * because the array ends unexpectely, or if the low char is there
0798:             * but its value is such that it is not a low surrogate.
0799:             *
0800:             * @param c the first (high) part of the surrogate, which
0801:             * must be confirmed before calling this method.
0802:             * @param ch Character array.
0803:             * @param i position Where the surrogate was detected.
0804:             * @param end The end index of the significant characters.
0805:             * @return 0 if the pair of characters was written out as-is,
0806:             * the unicode code point of the character represented by
0807:             * the surrogate pair if an entity reference with that value
0808:             * was written out. 
0809:             * 
0810:             * @throws IOException
0811:             * @throws org.xml.sax.SAXException if invalid UTF-16 surrogate detected.
0812:             */
0813:            protected int writeUTF16Surrogate(char c, char ch[], int i, int end)
0814:                    throws IOException {
0815:                int codePoint = 0;
0816:                if (i + 1 >= end) {
0817:                    throw new IOException(Utils.messages.createMessage(
0818:                            MsgKey.ER_INVALID_UTF16_SURROGATE,
0819:                            new Object[] { Integer.toHexString((int) c) }));
0820:                }
0821:
0822:                final char high = c;
0823:                final char low = ch[i + 1];
0824:                if (!Encodings.isLowUTF16Surrogate(low)) {
0825:                    throw new IOException(Utils.messages.createMessage(
0826:                            MsgKey.ER_INVALID_UTF16_SURROGATE,
0827:                            new Object[] { Integer.toHexString((int) c) + " "
0828:                                    + Integer.toHexString(low) }));
0829:                }
0830:
0831:                final java.io.Writer writer = m_writer;
0832:
0833:                // If we make it to here we have a valid high, low surrogate pair
0834:                if (m_encodingInfo.isInEncoding(c, low)) {
0835:                    // If the character formed by the surrogate pair
0836:                    // is in the encoding, so just write it out
0837:                    writer.write(ch, i, 2);
0838:                } else {
0839:                    // Don't know what to do with this char, it is
0840:                    // not in the encoding and not a high char in
0841:                    // a surrogate pair, so write out as an entity ref
0842:                    final String encoding = getEncoding();
0843:                    if (encoding != null) {
0844:                        /* The output encoding is known, 
0845:                         * so somthing is wrong.
0846:                         */
0847:                        codePoint = Encodings.toCodePoint(high, low);
0848:                        // not in the encoding, so write out a character reference
0849:                        writer.write('&');
0850:                        writer.write('#');
0851:                        writer.write(Integer.toString(codePoint));
0852:                        writer.write(';');
0853:                    } else {
0854:                        /* The output encoding is not known,
0855:                         * so just write it out as-is.
0856:                         */
0857:                        writer.write(ch, i, 2);
0858:                    }
0859:                }
0860:                // non-zero only if character reference was written out.
0861:                return codePoint;
0862:            }
0863:
0864:            /**
0865:             * Handle one of the default entities, return false if it
0866:             * is not a default entity.
0867:             *
0868:             * @param ch character to be escaped.
0869:             * @param i index into character array.
0870:             * @param chars non-null reference to character array.
0871:             * @param len length of chars.
0872:             * @param fromTextNode true if the characters being processed
0873:             * are from a text node, false if they are from an attribute value
0874:             * @param escLF true if the linefeed should be escaped.
0875:             *
0876:             * @return i+1 if the character was written, else i.
0877:             *
0878:             * @throws java.io.IOException
0879:             */
0880:            protected int accumDefaultEntity(java.io.Writer writer, char ch,
0881:                    int i, char[] chars, int len, boolean fromTextNode,
0882:                    boolean escLF) throws IOException {
0883:
0884:                if (!escLF && CharInfo.S_LINEFEED == ch) {
0885:                    writer.write(m_lineSep, 0, m_lineSepLen);
0886:                } else {
0887:                    // if this is text node character and a special one of those,
0888:                    // or if this is a character from attribute value and a special one of those
0889:                    if ((fromTextNode && m_charInfo.isSpecialTextChar(ch))
0890:                            || (!fromTextNode && m_charInfo
0891:                                    .isSpecialAttrChar(ch))) {
0892:                        String outputStringForChar = m_charInfo
0893:                                .getOutputStringForChar(ch);
0894:
0895:                        if (null != outputStringForChar) {
0896:                            writer.write(outputStringForChar);
0897:                        } else
0898:                            return i;
0899:                    } else
0900:                        return i;
0901:                }
0902:
0903:                return i + 1;
0904:
0905:            }
0906:
0907:            /**
0908:             * Normalize the characters, but don't escape.
0909:             *
0910:             * @param ch The characters from the XML document.
0911:             * @param start The start position in the array.
0912:             * @param length The number of characters to read from the array.
0913:             * @param isCData true if a CDATA block should be built around the characters.
0914:             * @param useSystemLineSeparator true if the operating systems 
0915:             * end-of-line separator should be output rather than a new-line character.
0916:             *
0917:             * @throws IOException
0918:             * @throws org.xml.sax.SAXException
0919:             */
0920:            void writeNormalizedChars(char ch[], int start, int length,
0921:                    boolean isCData, boolean useSystemLineSeparator)
0922:                    throws IOException, org.xml.sax.SAXException {
0923:                final java.io.Writer writer = m_writer;
0924:                int end = start + length;
0925:
0926:                for (int i = start; i < end; i++) {
0927:                    char c = ch[i];
0928:
0929:                    if (CharInfo.S_LINEFEED == c && useSystemLineSeparator) {
0930:                        writer.write(m_lineSep, 0, m_lineSepLen);
0931:                    } else if (isCData && (!escapingNotNeeded(c))) {
0932:                        //                if (i != 0)
0933:                        if (m_cdataTagOpen)
0934:                            closeCDATA();
0935:
0936:                        // This needs to go into a function... 
0937:                        if (Encodings.isHighUTF16Surrogate(c)) {
0938:                            writeUTF16Surrogate(c, ch, i, end);
0939:                            i++; // process two input characters
0940:                        } else {
0941:                            writer.write("&#");
0942:
0943:                            String intStr = Integer.toString((int) c);
0944:
0945:                            writer.write(intStr);
0946:                            writer.write(';');
0947:                        }
0948:
0949:                        //                if ((i != 0) && (i < (end - 1)))
0950:                        //                if (!m_cdataTagOpen && (i < (end - 1)))
0951:                        //                {
0952:                        //                    writer.write(CDATA_DELIMITER_OPEN);
0953:                        //                    m_cdataTagOpen = true;
0954:                        //                }
0955:                    } else if (isCData
0956:                            && ((i < (end - 2)) && (']' == c)
0957:                                    && (']' == ch[i + 1]) && ('>' == ch[i + 2]))) {
0958:                        writer.write(CDATA_CONTINUE);
0959:
0960:                        i += 2;
0961:                    } else {
0962:                        if (escapingNotNeeded(c)) {
0963:                            if (isCData && !m_cdataTagOpen) {
0964:                                writer.write(CDATA_DELIMITER_OPEN);
0965:                                m_cdataTagOpen = true;
0966:                            }
0967:                            writer.write(c);
0968:                        }
0969:
0970:                        // This needs to go into a function... 
0971:                        else if (Encodings.isHighUTF16Surrogate(c)) {
0972:                            if (m_cdataTagOpen)
0973:                                closeCDATA();
0974:                            writeUTF16Surrogate(c, ch, i, end);
0975:                            i++; // process two input characters
0976:                        } else {
0977:                            if (m_cdataTagOpen)
0978:                                closeCDATA();
0979:                            writer.write("&#");
0980:
0981:                            String intStr = Integer.toString((int) c);
0982:
0983:                            writer.write(intStr);
0984:                            writer.write(';');
0985:                        }
0986:                    }
0987:                }
0988:
0989:            }
0990:
0991:            /**
0992:             * Ends an un-escaping section.
0993:             *
0994:             * @see #startNonEscaping
0995:             *
0996:             * @throws org.xml.sax.SAXException
0997:             */
0998:            public void endNonEscaping() throws org.xml.sax.SAXException {
0999:                m_disableOutputEscapingStates.pop();
1000:            }
1001:
1002:            /**
1003:             * Starts an un-escaping section. All characters printed within an un-
1004:             * escaping section are printed as is, without escaping special characters
1005:             * into entity references. Only XML and HTML serializers need to support
1006:             * this method.
1007:             * <p> The contents of the un-escaping section will be delivered through the
1008:             * regular <tt>characters</tt> event.
1009:             *
1010:             * @throws org.xml.sax.SAXException
1011:             */
1012:            public void startNonEscaping() throws org.xml.sax.SAXException {
1013:                m_disableOutputEscapingStates.push(true);
1014:            }
1015:
1016:            /**
1017:             * Receive notification of cdata.
1018:             *
1019:             * <p>The Parser will call this method to report each chunk of
1020:             * character data.  SAX parsers may return all contiguous character
1021:             * data in a single chunk, or they may split it into several
1022:             * chunks; however, all of the characters in any single event
1023:             * must come from the same external entity, so that the Locator
1024:             * provides useful information.</p>
1025:             *
1026:             * <p>The application must not attempt to read from the array
1027:             * outside of the specified range.</p>
1028:             *
1029:             * <p>Note that some parsers will report whitespace using the
1030:             * ignorableWhitespace() method rather than this one (validating
1031:             * parsers must do so).</p>
1032:             *
1033:             * @param ch The characters from the XML document.
1034:             * @param start The start position in the array.
1035:             * @param length The number of characters to read from the array.
1036:             * @throws org.xml.sax.SAXException Any SAX exception, possibly
1037:             *            wrapping another exception.
1038:             * @see #ignorableWhitespace
1039:             * @see org.xml.sax.Locator
1040:             *
1041:             * @throws org.xml.sax.SAXException
1042:             */
1043:            protected void cdata(char ch[], int start, final int length)
1044:                    throws org.xml.sax.SAXException {
1045:
1046:                try {
1047:                    final int old_start = start;
1048:                    if (m_elemContext.m_startTagOpen) {
1049:                        closeStartTag();
1050:                        m_elemContext.m_startTagOpen = false;
1051:                    }
1052:                    m_ispreserve = true;
1053:
1054:                    if (shouldIndent())
1055:                        indent();
1056:
1057:                    boolean writeCDataBrackets = (((length >= 1) && escapingNotNeeded(ch[start])));
1058:
1059:                    /* Write out the CDATA opening delimiter only if
1060:                     * we are supposed to, and if we are not already in
1061:                     * the middle of a CDATA section  
1062:                     */
1063:                    if (writeCDataBrackets && !m_cdataTagOpen) {
1064:                        m_writer.write(CDATA_DELIMITER_OPEN);
1065:                        m_cdataTagOpen = true;
1066:                    }
1067:
1068:                    // writer.write(ch, start, length);
1069:                    if (isEscapingDisabled()) {
1070:                        charactersRaw(ch, start, length);
1071:                    } else
1072:                        writeNormalizedChars(ch, start, length, true,
1073:                                m_lineSepUse);
1074:
1075:                    /* used to always write out CDATA closing delimiter here,
1076:                     * but now we delay, so that we can merge CDATA sections on output.    
1077:                     * need to write closing delimiter later
1078:                     */
1079:                    if (writeCDataBrackets) {
1080:                        /* if the CDATA section ends with ] don't leave it open
1081:                         * as there is a chance that an adjacent CDATA sections
1082:                         * starts with ]>.  
1083:                         * We don't want to merge ]] with > , or ] with ]> 
1084:                         */
1085:                        if (ch[start + length - 1] == ']')
1086:                            closeCDATA();
1087:                    }
1088:
1089:                    // time to fire off CDATA event
1090:                    if (m_tracer != null)
1091:                        super .fireCDATAEvent(ch, old_start, length);
1092:                } catch (IOException ioe) {
1093:                    throw new org.xml.sax.SAXException(Utils.messages
1094:                            .createMessage(MsgKey.ER_OIERROR, null), ioe);
1095:                    //"IO error", ioe);
1096:                }
1097:            }
1098:
1099:            /**
1100:             * Tell if the character escaping should be disabled for the current state.
1101:             *
1102:             * @return true if the character escaping should be disabled.
1103:             */
1104:            private boolean isEscapingDisabled() {
1105:                return m_disableOutputEscapingStates.peekOrFalse();
1106:            }
1107:
1108:            /**
1109:             * If available, when the disable-output-escaping attribute is used,
1110:             * output raw text without escaping.
1111:             *
1112:             * @param ch The characters from the XML document.
1113:             * @param start The start position in the array.
1114:             * @param length The number of characters to read from the array.
1115:             *
1116:             * @throws org.xml.sax.SAXException
1117:             */
1118:            protected void charactersRaw(char ch[], int start, int length)
1119:                    throws org.xml.sax.SAXException {
1120:
1121:                if (m_inEntityRef)
1122:                    return;
1123:                try {
1124:                    if (m_elemContext.m_startTagOpen) {
1125:                        closeStartTag();
1126:                        m_elemContext.m_startTagOpen = false;
1127:                    }
1128:
1129:                    m_ispreserve = true;
1130:
1131:                    m_writer.write(ch, start, length);
1132:                } catch (IOException e) {
1133:                    throw new SAXException(e);
1134:                }
1135:
1136:            }
1137:
1138:            /**
1139:             * Receive notification of character data.
1140:             *
1141:             * <p>The Parser will call this method to report each chunk of
1142:             * character data.  SAX parsers may return all contiguous character
1143:             * data in a single chunk, or they may split it into several
1144:             * chunks; however, all of the characters in any single event
1145:             * must come from the same external entity, so that the Locator
1146:             * provides useful information.</p>
1147:             *
1148:             * <p>The application must not attempt to read from the array
1149:             * outside of the specified range.</p>
1150:             *
1151:             * <p>Note that some parsers will report whitespace using the
1152:             * ignorableWhitespace() method rather than this one (validating
1153:             * parsers must do so).</p>
1154:             *
1155:             * @param chars The characters from the XML document.
1156:             * @param start The start position in the array.
1157:             * @param length The number of characters to read from the array.
1158:             * @throws org.xml.sax.SAXException Any SAX exception, possibly
1159:             *            wrapping another exception.
1160:             * @see #ignorableWhitespace
1161:             * @see org.xml.sax.Locator
1162:             *
1163:             * @throws org.xml.sax.SAXException
1164:             */
1165:            public void characters(final char chars[], final int start,
1166:                    final int length) throws org.xml.sax.SAXException {
1167:                // It does not make sense to continue with rest of the method if the number of 
1168:                // characters to read from array is 0.
1169:                // Section 7.6.1 of XSLT 1.0 (http://www.w3.org/TR/xslt#value-of) suggest no text node
1170:                // is created if string is empty.	
1171:                if (length == 0 || (m_inEntityRef && !m_expandDTDEntities))
1172:                    return;
1173:                if (m_elemContext.m_startTagOpen) {
1174:                    closeStartTag();
1175:                    m_elemContext.m_startTagOpen = false;
1176:                } else if (m_needToCallStartDocument) {
1177:                    startDocumentInternal();
1178:                }
1179:
1180:                if (m_cdataStartCalled || m_elemContext.m_isCdataSection) {
1181:                    /* either due to startCDATA() being called or due to 
1182:                     * cdata-section-elements atribute, we need this as cdata
1183:                     */
1184:                    cdata(chars, start, length);
1185:
1186:                    return;
1187:                }
1188:
1189:                if (m_cdataTagOpen)
1190:                    closeCDATA();
1191:                // the check with _escaping is a bit of a hack for XLSTC
1192:
1193:                if (m_disableOutputEscapingStates.peekOrFalse()
1194:                        || (!m_escaping)) {
1195:                    charactersRaw(chars, start, length);
1196:
1197:                    // time to fire off characters generation event
1198:                    if (m_tracer != null)
1199:                        super .fireCharEvent(chars, start, length);
1200:
1201:                    return;
1202:                }
1203:
1204:                if (m_elemContext.m_startTagOpen) {
1205:                    closeStartTag();
1206:                    m_elemContext.m_startTagOpen = false;
1207:                }
1208:
1209:                try {
1210:                    int i;
1211:                    char ch1;
1212:                    int startClean;
1213:
1214:                    // skip any leading whitspace 
1215:                    // don't go off the end and use a hand inlined version
1216:                    // of isWhitespace(ch)
1217:                    final int end = start + length;
1218:                    int lastDirty = start - 1; // last character that needed processing
1219:                    for (i = start; ((i < end) && ((ch1 = chars[i]) == 0x20
1220:                            || (ch1 == 0xA && m_lineSepUse) || ch1 == 0xD || ch1 == 0x09)); i++) {
1221:                        /*
1222:                         * We are processing leading whitespace, but are doing the same
1223:                         * processing for dirty characters here as for non-whitespace.
1224:                         * 
1225:                         */
1226:                        if (!m_charInfo.isTextASCIIClean(ch1)) {
1227:                            lastDirty = processDirty(chars, end, i, ch1,
1228:                                    lastDirty, true);
1229:                            i = lastDirty;
1230:                        }
1231:                    }
1232:                    /* If there is some non-whitespace, mark that we may need
1233:                     * to preserve this. This is only important if we have indentation on.
1234:                     */
1235:                    if (i < end)
1236:                        m_ispreserve = true;
1237:
1238:                    //            int lengthClean;    // number of clean characters in a row
1239:                    //            final boolean[] isAsciiClean = m_charInfo.getASCIIClean();
1240:
1241:                    final boolean isXML10 = XMLVERSION10.equals(getVersion());
1242:                    // we've skipped the leading whitespace, now deal with the rest
1243:                    for (; i < end; i++) {
1244:                        {
1245:                            // A tight loop to skip over common clean chars
1246:                            // This tight loop makes it easier for the JIT
1247:                            // to optimize.
1248:                            char ch2;
1249:                            while (i < end && ((ch2 = chars[i]) < 127)
1250:                                    && m_charInfo.isTextASCIIClean(ch2))
1251:                                i++;
1252:                            if (i == end)
1253:                                break;
1254:                        }
1255:
1256:                        final char ch = chars[i];
1257:                        /*  The check for isCharacterInC0orC1Ranger and 
1258:                         *  isNELorLSEPCharacter has been added
1259:                         *  to support Control Characters in XML 1.1
1260:                         */
1261:                        if (!isCharacterInC0orC1Range(ch)
1262:                                && (isXML10 || !isNELorLSEPCharacter(ch))
1263:                                && (escapingNotNeeded(ch) && (!m_charInfo
1264:                                        .isSpecialTextChar(ch))) || ('"' == ch)) {
1265:                            ; // a character needing no special processing
1266:                        } else {
1267:                            lastDirty = processDirty(chars, end, i, ch,
1268:                                    lastDirty, true);
1269:                            i = lastDirty;
1270:                        }
1271:                    }
1272:
1273:                    // we've reached the end. Any clean characters at the
1274:                    // end of the array than need to be written out?
1275:                    startClean = lastDirty + 1;
1276:                    if (i > startClean) {
1277:                        int lengthClean = i - startClean;
1278:                        m_writer.write(chars, startClean, lengthClean);
1279:                    }
1280:
1281:                    // For indentation purposes, mark that we've just writen text out
1282:                    m_isprevtext = true;
1283:                } catch (IOException e) {
1284:                    throw new SAXException(e);
1285:                }
1286:
1287:                // time to fire off characters generation event
1288:                if (m_tracer != null)
1289:                    super .fireCharEvent(chars, start, length);
1290:            }
1291:
1292:            /**
1293:             * This method checks if a given character is between C0 or C1 range
1294:             * of Control characters.
1295:             * This method is added to support Control Characters for XML 1.1
1296:             * If a given character is TAB (0x09), LF (0x0A) or CR (0x0D), this method
1297:             * return false. Since they are whitespace characters, no special processing is needed.
1298:             * 
1299:             * @param ch
1300:             * @return boolean
1301:             */
1302:            private static boolean isCharacterInC0orC1Range(char ch) {
1303:                if (ch == 0x09 || ch == 0x0A || ch == 0x0D)
1304:                    return false;
1305:                else
1306:                    return (ch >= 0x7F && ch <= 0x9F)
1307:                            || (ch >= 0x01 && ch <= 0x1F);
1308:            }
1309:
1310:            /**
1311:             * This method checks if a given character either NEL (0x85) or LSEP (0x2028)
1312:             * These are new end of line charcters added in XML 1.1.  These characters must be
1313:             * written as Numeric Character References (NCR) in XML 1.1 output document.
1314:             * 
1315:             * @param ch
1316:             * @return boolean
1317:             */
1318:            private static boolean isNELorLSEPCharacter(char ch) {
1319:                return (ch == 0x85 || ch == 0x2028);
1320:            }
1321:
1322:            /**
1323:             * Process a dirty character and any preeceding clean characters
1324:             * that were not yet processed.
1325:             * @param chars array of characters being processed
1326:             * @param end one (1) beyond the last character 
1327:             * in chars to be processed
1328:             * @param i the index of the dirty character
1329:             * @param ch the character in chars[i]
1330:             * @param lastDirty the last dirty character previous to i
1331:             * @param fromTextNode true if the characters being processed are
1332:             * from a text node, false if they are from an attribute value.
1333:             * @return the index of the last character processed
1334:             */
1335:            private int processDirty(char[] chars, int end, int i, char ch,
1336:                    int lastDirty, boolean fromTextNode) throws IOException {
1337:                int startClean = lastDirty + 1;
1338:                // if we have some clean characters accumulated
1339:                // process them before the dirty one.                   
1340:                if (i > startClean) {
1341:                    int lengthClean = i - startClean;
1342:                    m_writer.write(chars, startClean, lengthClean);
1343:                }
1344:
1345:                // process the "dirty" character
1346:                if (CharInfo.S_LINEFEED == ch && fromTextNode) {
1347:                    m_writer.write(m_lineSep, 0, m_lineSepLen);
1348:                } else {
1349:                    startClean = accumDefaultEscape(m_writer, (char) ch, i,
1350:                            chars, end, fromTextNode, false);
1351:                    i = startClean - 1;
1352:                }
1353:                // Return the index of the last character that we just processed 
1354:                // which is a dirty character.
1355:                return i;
1356:            }
1357:
1358:            /**
1359:             * Receive notification of character data.
1360:             *
1361:             * @param s The string of characters to process.
1362:             *
1363:             * @throws org.xml.sax.SAXException
1364:             */
1365:            public void characters(String s) throws org.xml.sax.SAXException {
1366:                if (m_inEntityRef && !m_expandDTDEntities)
1367:                    return;
1368:                final int length = s.length();
1369:                if (length > m_charsBuff.length) {
1370:                    m_charsBuff = new char[length * 2 + 1];
1371:                }
1372:                s.getChars(0, length, m_charsBuff, 0);
1373:                characters(m_charsBuff, 0, length);
1374:            }
1375:
1376:            /**
1377:             * Escape and writer.write a character.
1378:             *
1379:             * @param ch character to be escaped.
1380:             * @param i index into character array.
1381:             * @param chars non-null reference to character array.
1382:             * @param len length of chars.
1383:             * @param fromTextNode true if the characters being processed are
1384:             * from a text node, false if the characters being processed are from
1385:             * an attribute value.
1386:             * @param escLF true if the linefeed should be escaped.
1387:             *
1388:             * @return i+1 if a character was written, i+2 if two characters
1389:             * were written out, else return i.
1390:             *
1391:             * @throws org.xml.sax.SAXException
1392:             */
1393:            protected int accumDefaultEscape(Writer writer, char ch, int i,
1394:                    char[] chars, int len, boolean fromTextNode, boolean escLF)
1395:                    throws IOException {
1396:
1397:                int pos = accumDefaultEntity(writer, ch, i, chars, len,
1398:                        fromTextNode, escLF);
1399:
1400:                if (i == pos) {
1401:                    if (Encodings.isHighUTF16Surrogate(ch)) {
1402:
1403:                        // Should be the UTF-16 low surrogate of the hig/low pair.
1404:                        char next;
1405:                        // Unicode code point formed from the high/low pair.
1406:                        int codePoint = 0;
1407:
1408:                        if (i + 1 >= len) {
1409:                            throw new IOException(Utils.messages.createMessage(
1410:                                    MsgKey.ER_INVALID_UTF16_SURROGATE,
1411:                                    new Object[] { Integer.toHexString(ch) }));
1412:                            //"Invalid UTF-16 surrogate detected: "
1413:
1414:                            //+Integer.toHexString(ch)+ " ?");
1415:                        } else {
1416:                            next = chars[++i];
1417:
1418:                            if (!(Encodings.isLowUTF16Surrogate(next)))
1419:                                throw new IOException(
1420:                                        Utils.messages
1421:                                                .createMessage(
1422:                                                        MsgKey.ER_INVALID_UTF16_SURROGATE,
1423:                                                        new Object[] { Integer
1424:                                                                .toHexString(ch)
1425:                                                                + " "
1426:                                                                + Integer
1427:                                                                        .toHexString(next) }));
1428:                            //"Invalid UTF-16 surrogate detected: "
1429:
1430:                            //+Integer.toHexString(ch)+" "+Integer.toHexString(next));
1431:                            codePoint = Encodings.toCodePoint(ch, next);
1432:                        }
1433:
1434:                        writer.write("&#");
1435:                        writer.write(Integer.toString(codePoint));
1436:                        writer.write(';');
1437:                        pos += 2; // count the two characters that went into writing out this entity
1438:                    } else {
1439:                        /*  This if check is added to support control characters in XML 1.1.
1440:                         *  If a character is a Control Character within C0 and C1 range, it is desirable
1441:                         *  to write it out as Numeric Character Reference(NCR) regardless of XML Version
1442:                         *  being used for output document.
1443:                         */
1444:                        if (isCharacterInC0orC1Range(ch)
1445:                                || (XMLVERSION11.equals(getVersion()) && isNELorLSEPCharacter(ch))) {
1446:                            writer.write("&#");
1447:                            writer.write(Integer.toString(ch));
1448:                            writer.write(';');
1449:                        } else if ((!escapingNotNeeded(ch) || ((fromTextNode && m_charInfo
1450:                                .isSpecialTextChar(ch)) || (!fromTextNode && m_charInfo
1451:                                .isSpecialAttrChar(ch))))
1452:                                && m_elemContext.m_currentElemDepth > 0) {
1453:                            writer.write("&#");
1454:                            writer.write(Integer.toString(ch));
1455:                            writer.write(';');
1456:                        } else {
1457:                            writer.write(ch);
1458:                        }
1459:                        pos++; // count the single character that was processed
1460:                    }
1461:
1462:                }
1463:                return pos;
1464:            }
1465:
1466:            /**
1467:             * Receive notification of the beginning of an element, although this is a
1468:             * SAX method additional namespace or attribute information can occur before
1469:             * or after this call, that is associated with this element.
1470:             *
1471:             *
1472:             * @param namespaceURI The Namespace URI, or the empty string if the
1473:             *        element has no Namespace URI or if Namespace
1474:             *        processing is not being performed.
1475:             * @param localName The local name (without prefix), or the
1476:             *        empty string if Namespace processing is not being
1477:             *        performed.
1478:             * @param name The element type name.
1479:             * @param atts The attributes attached to the element, if any.
1480:             * @throws org.xml.sax.SAXException Any SAX exception, possibly
1481:             *            wrapping another exception.
1482:             * @see org.xml.sax.ContentHandler#startElement
1483:             * @see org.xml.sax.ContentHandler#endElement
1484:             * @see org.xml.sax.AttributeList
1485:             *
1486:             * @throws org.xml.sax.SAXException
1487:             */
1488:            public void startElement(String namespaceURI, String localName,
1489:                    String name, Attributes atts)
1490:                    throws org.xml.sax.SAXException {
1491:                if (m_inEntityRef)
1492:                    return;
1493:
1494:                if (m_needToCallStartDocument) {
1495:                    startDocumentInternal();
1496:                    m_needToCallStartDocument = false;
1497:                } else if (m_cdataTagOpen)
1498:                    closeCDATA();
1499:                try {
1500:                    if ((true == m_needToOutputDocTypeDecl)
1501:                            && (null != getDoctypeSystem())) {
1502:                        outputDocTypeDecl(name, true);
1503:                    }
1504:
1505:                    m_needToOutputDocTypeDecl = false;
1506:
1507:                    /* before we over-write the current elementLocalName etc.
1508:                     * lets close out the old one (if we still need to)
1509:                     */
1510:                    if (m_elemContext.m_startTagOpen) {
1511:                        closeStartTag();
1512:                        m_elemContext.m_startTagOpen = false;
1513:                    }
1514:
1515:                    if (namespaceURI != null)
1516:                        ensurePrefixIsDeclared(namespaceURI, name);
1517:
1518:                    m_ispreserve = false;
1519:
1520:                    if (shouldIndent() && m_startNewLine) {
1521:                        indent();
1522:                    }
1523:
1524:                    m_startNewLine = true;
1525:
1526:                    final java.io.Writer writer = m_writer;
1527:                    writer.write('<');
1528:                    writer.write(name);
1529:                } catch (IOException e) {
1530:                    throw new SAXException(e);
1531:                }
1532:
1533:                // process the attributes now, because after this SAX call they might be gone
1534:                if (atts != null)
1535:                    addAttributes(atts);
1536:
1537:                m_elemContext = m_elemContext.push(namespaceURI, localName,
1538:                        name);
1539:                m_isprevtext = false;
1540:
1541:                if (m_tracer != null)
1542:                    firePseudoAttributes();
1543:            }
1544:
1545:            /**
1546:             * Receive notification of the beginning of an element, additional
1547:             * namespace or attribute information can occur before or after this call,
1548:             * that is associated with this element.
1549:             *
1550:             *
1551:             * @param elementNamespaceURI The Namespace URI, or the empty string if the
1552:             *        element has no Namespace URI or if Namespace
1553:             *        processing is not being performed.
1554:             * @param elementLocalName The local name (without prefix), or the
1555:             *        empty string if Namespace processing is not being
1556:             *        performed.
1557:             * @param elementName The element type name.
1558:             * @throws org.xml.sax.SAXException Any SAX exception, possibly
1559:             *            wrapping another exception.
1560:             * @see org.xml.sax.ContentHandler#startElement
1561:             * @see org.xml.sax.ContentHandler#endElement
1562:             * @see org.xml.sax.AttributeList
1563:             *
1564:             * @throws org.xml.sax.SAXException
1565:             */
1566:            public void startElement(String elementNamespaceURI,
1567:                    String elementLocalName, String elementName)
1568:                    throws SAXException {
1569:                startElement(elementNamespaceURI, elementLocalName,
1570:                        elementName, null);
1571:            }
1572:
1573:            public void startElement(String elementName) throws SAXException {
1574:                startElement(null, null, elementName, null);
1575:            }
1576:
1577:            /**
1578:             * Output the doc type declaration.
1579:             *
1580:             * @param name non-null reference to document type name.
1581:             * NEEDSDOC @param closeDecl
1582:             *
1583:             * @throws java.io.IOException
1584:             */
1585:            void outputDocTypeDecl(String name, boolean closeDecl)
1586:                    throws SAXException {
1587:                if (m_cdataTagOpen)
1588:                    closeCDATA();
1589:                try {
1590:                    final java.io.Writer writer = m_writer;
1591:                    writer.write("<!DOCTYPE ");
1592:                    writer.write(name);
1593:
1594:                    String doctypePublic = getDoctypePublic();
1595:                    if (null != doctypePublic) {
1596:                        writer.write(" PUBLIC \"");
1597:                        writer.write(doctypePublic);
1598:                        writer.write('\"');
1599:                    }
1600:
1601:                    String doctypeSystem = getDoctypeSystem();
1602:                    if (null != doctypeSystem) {
1603:                        if (null == doctypePublic)
1604:                            writer.write(" SYSTEM \"");
1605:                        else
1606:                            writer.write(" \"");
1607:
1608:                        writer.write(doctypeSystem);
1609:
1610:                        if (closeDecl) {
1611:                            writer.write("\">");
1612:                            writer.write(m_lineSep, 0, m_lineSepLen);
1613:                            closeDecl = false; // done closing
1614:                        } else
1615:                            writer.write('\"');
1616:                    }
1617:                    boolean dothis  = false;
1618:                    if (dothis ) {
1619:                        // at one point this code seemed right,
1620:                        // but not anymore - Brian M.
1621:                        if (closeDecl) {
1622:                            writer.write('>');
1623:                            writer.write(m_lineSep, 0, m_lineSepLen);
1624:                        }
1625:                    }
1626:                } catch (IOException e) {
1627:                    throw new SAXException(e);
1628:                }
1629:            }
1630:
1631:            /**
1632:             * Process the attributes, which means to write out the currently
1633:             * collected attributes to the writer. The attributes are not
1634:             * cleared by this method
1635:             * 
1636:             * @param writer the writer to write processed attributes to.
1637:             * @param nAttrs the number of attributes in m_attributes 
1638:             * to be processed
1639:             *
1640:             * @throws java.io.IOException
1641:             * @throws org.xml.sax.SAXException
1642:             */
1643:            public void processAttributes(java.io.Writer writer, int nAttrs)
1644:                    throws IOException, SAXException {
1645:                /* real SAX attributes are not passed in, so process the 
1646:                 * attributes that were collected after the startElement call.
1647:                 * _attribVector is a "cheap" list for Stream serializer output
1648:                 * accumulated over a series of calls to attribute(name,value)
1649:                 */
1650:
1651:                String encoding = getEncoding();
1652:                for (int i = 0; i < nAttrs; i++) {
1653:                    // elementAt is JDK 1.1.8
1654:                    final String name = m_attributes.getQName(i);
1655:                    final String value = m_attributes.getValue(i);
1656:                    writer.write(' ');
1657:                    writer.write(name);
1658:                    writer.write("=\"");
1659:                    writeAttrString(writer, value, encoding);
1660:                    writer.write('\"');
1661:                }
1662:            }
1663:
1664:            /**
1665:             * Returns the specified <var>string</var> after substituting <VAR>specials</VAR>,
1666:             * and UTF-16 surrogates for chracter references <CODE>&amp;#xnn</CODE>.
1667:             *
1668:             * @param   string      String to convert to XML format.
1669:             * @param   encoding    CURRENTLY NOT IMPLEMENTED.
1670:             *
1671:             * @throws java.io.IOException
1672:             */
1673:            public void writeAttrString(Writer writer, String string,
1674:                    String encoding) throws IOException {
1675:                final int len = string.length();
1676:                if (len > m_attrBuff.length) {
1677:                    m_attrBuff = new char[len * 2 + 1];
1678:                }
1679:                string.getChars(0, len, m_attrBuff, 0);
1680:                final char[] stringChars = m_attrBuff;
1681:
1682:                for (int i = 0; i < len; i++) {
1683:                    char ch = stringChars[i];
1684:                    if (escapingNotNeeded(ch)
1685:                            && (!m_charInfo.isSpecialAttrChar(ch))) {
1686:                        writer.write(ch);
1687:                    } else { // I guess the parser doesn't normalize cr/lf in attributes. -sb
1688:                    //                if ((CharInfo.S_CARRIAGERETURN == ch)
1689:                    //                    && ((i + 1) < len)
1690:                    //                    && (CharInfo.S_LINEFEED == stringChars[i + 1]))
1691:                    //                {
1692:                    //                    i++;
1693:                    //                    ch = CharInfo.S_LINEFEED;
1694:                    //                }
1695:
1696:                        accumDefaultEscape(writer, ch, i, stringChars, len,
1697:                                false, true);
1698:                    }
1699:                }
1700:
1701:            }
1702:
1703:            /**
1704:             * Receive notification of the end of an element.
1705:             *
1706:             *
1707:             * @param namespaceURI The Namespace URI, or the empty string if the
1708:             *        element has no Namespace URI or if Namespace
1709:             *        processing is not being performed.
1710:             * @param localName The local name (without prefix), or the
1711:             *        empty string if Namespace processing is not being
1712:             *        performed.
1713:             * @param name The element type name
1714:             * @throws org.xml.sax.SAXException Any SAX exception, possibly
1715:             *            wrapping another exception.
1716:             *
1717:             * @throws org.xml.sax.SAXException
1718:             */
1719:            public void endElement(String namespaceURI, String localName,
1720:                    String name) throws org.xml.sax.SAXException {
1721:                if (m_inEntityRef)
1722:                    return;
1723:
1724:                // namespaces declared at the current depth are no longer valid
1725:                // so get rid of them    
1726:                m_prefixMap.popNamespaces(m_elemContext.m_currentElemDepth,
1727:                        null);
1728:
1729:                try {
1730:                    final java.io.Writer writer = m_writer;
1731:                    if (m_elemContext.m_startTagOpen) {
1732:                        if (m_tracer != null)
1733:                            super .fireStartElem(m_elemContext.m_elementName);
1734:                        int nAttrs = m_attributes.getLength();
1735:                        if (nAttrs > 0) {
1736:                            processAttributes(m_writer, nAttrs);
1737:                            // clear attributes object for re-use with next element
1738:                            m_attributes.clear();
1739:                        }
1740:                        if (m_spaceBeforeClose)
1741:                            writer.write(" />");
1742:                        else
1743:                            writer.write("/>");
1744:                        /* don't need to pop cdataSectionState because
1745:                         * this element ended so quickly that we didn't get
1746:                         * to push the state.
1747:                         */
1748:
1749:                    } else {
1750:                        if (m_cdataTagOpen)
1751:                            closeCDATA();
1752:
1753:                        if (shouldIndent())
1754:                            indent(m_elemContext.m_currentElemDepth - 1);
1755:                        writer.write('<');
1756:                        writer.write('/');
1757:                        writer.write(name);
1758:                        writer.write('>');
1759:                    }
1760:                } catch (IOException e) {
1761:                    throw new SAXException(e);
1762:                }
1763:
1764:                if (!m_elemContext.m_startTagOpen && m_doIndent) {
1765:                    m_ispreserve = m_preserves.isEmpty() ? false : m_preserves
1766:                            .pop();
1767:                }
1768:
1769:                m_isprevtext = false;
1770:
1771:                // fire off the end element event
1772:                if (m_tracer != null)
1773:                    super .fireEndElem(name);
1774:                m_elemContext = m_elemContext.m_prev;
1775:            }
1776:
1777:            /**
1778:             * Receive notification of the end of an element.
1779:             * @param name The element type name
1780:             * @throws org.xml.sax.SAXException Any SAX exception, possibly
1781:             *     wrapping another exception.
1782:             */
1783:            public void endElement(String name) throws org.xml.sax.SAXException {
1784:                endElement(null, null, name);
1785:            }
1786:
1787:            /**
1788:             * Begin the scope of a prefix-URI Namespace mapping
1789:             * just before another element is about to start.
1790:             * This call will close any open tags so that the prefix mapping
1791:             * will not apply to the current element, but the up comming child.
1792:             * 
1793:             * @see org.xml.sax.ContentHandler#startPrefixMapping
1794:             * 
1795:             * @param prefix The Namespace prefix being declared.
1796:             * @param uri The Namespace URI the prefix is mapped to.
1797:             * 
1798:             * @throws org.xml.sax.SAXException The client may throw
1799:             *            an exception during processing.
1800:             * 
1801:             */
1802:            public void startPrefixMapping(String prefix, String uri)
1803:                    throws org.xml.sax.SAXException {
1804:                // the "true" causes the flush of any open tags
1805:                startPrefixMapping(prefix, uri, true);
1806:            }
1807:
1808:            /**
1809:             * Handle a prefix/uri mapping, which is associated with a startElement()
1810:             * that is soon to follow. Need to close any open start tag to make
1811:             * sure than any name space attributes due to this event are associated wih
1812:             * the up comming element, not the current one.
1813:             * @see ExtendedContentHandler#startPrefixMapping
1814:             *
1815:             * @param prefix The Namespace prefix being declared.
1816:             * @param uri The Namespace URI the prefix is mapped to.
1817:             * @param shouldFlush true if any open tags need to be closed first, this
1818:             * will impact which element the mapping applies to (open parent, or its up
1819:             * comming child)
1820:             * @return returns true if the call made a change to the current 
1821:             * namespace information, false if it did not change anything, e.g. if the
1822:             * prefix/namespace mapping was already in scope from before.
1823:             * 
1824:             * @throws org.xml.sax.SAXException The client may throw
1825:             *            an exception during processing.
1826:             *
1827:             *
1828:             */
1829:            public boolean startPrefixMapping(String prefix, String uri,
1830:                    boolean shouldFlush) throws org.xml.sax.SAXException {
1831:
1832:                /* Remember the mapping, and at what depth it was declared
1833:                 * This is one greater than the current depth because these
1834:                 * mappings will apply to the next depth. This is in
1835:                 * consideration that startElement() will soon be called
1836:                 */
1837:
1838:                boolean pushed;
1839:                int pushDepth;
1840:                if (shouldFlush) {
1841:                    flushPending();
1842:                    // the prefix mapping applies to the child element (one deeper)
1843:                    pushDepth = m_elemContext.m_currentElemDepth + 1;
1844:                } else {
1845:                    // the prefix mapping applies to the current element
1846:                    pushDepth = m_elemContext.m_currentElemDepth;
1847:                }
1848:                pushed = m_prefixMap.pushNamespace(prefix, uri, pushDepth);
1849:
1850:                if (pushed) {
1851:                    /* Brian M.: don't know if we really needto do this. The
1852:                     * callers of this object should have injected both
1853:                     * startPrefixMapping and the attributes.  We are 
1854:                     * just covering our butt here.
1855:                     */
1856:                    String name;
1857:                    if (EMPTYSTRING.equals(prefix)) {
1858:                        name = "xmlns";
1859:                        addAttributeAlways(XMLNS_URI, name, name, "CDATA", uri,
1860:                                false);
1861:                    } else {
1862:                        if (!EMPTYSTRING.equals(uri))
1863:                        // hack for XSLTC attribset16 test
1864:                        { // that maps ns1 prefix to "" URI
1865:                            name = "xmlns:" + prefix;
1866:
1867:                            /* for something like xmlns:abc="w3.pretend.org"
1868:                             *  the      uri is the value, that is why we pass it in the
1869:                             * value, or 5th slot of addAttributeAlways()
1870:                             */
1871:                            addAttributeAlways(XMLNS_URI, prefix, name,
1872:                                    "CDATA", uri, false);
1873:                        }
1874:                    }
1875:                }
1876:                return pushed;
1877:            }
1878:
1879:            /**
1880:             * Receive notification of an XML comment anywhere in the document. This
1881:             * callback will be used for comments inside or outside the document
1882:             * element, including comments in the external DTD subset (if read).
1883:             * @param ch An array holding the characters in the comment.
1884:             * @param start The starting position in the array.
1885:             * @param length The number of characters to use from the array.
1886:             * @throws org.xml.sax.SAXException The application may raise an exception.
1887:             */
1888:            public void comment(char ch[], int start, int length)
1889:                    throws org.xml.sax.SAXException {
1890:
1891:                int start_old = start;
1892:                if (m_inEntityRef)
1893:                    return;
1894:                if (m_elemContext.m_startTagOpen) {
1895:                    closeStartTag();
1896:                    m_elemContext.m_startTagOpen = false;
1897:                } else if (m_needToCallStartDocument) {
1898:                    startDocumentInternal();
1899:                    m_needToCallStartDocument = false;
1900:                }
1901:
1902:                try {
1903:                    if (shouldIndent())
1904:                        indent();
1905:
1906:                    final int limit = start + length;
1907:                    boolean wasDash = false;
1908:                    if (m_cdataTagOpen)
1909:                        closeCDATA();
1910:                    final java.io.Writer writer = m_writer;
1911:                    writer.write(COMMENT_BEGIN);
1912:                    // Detect occurrences of two consecutive dashes, handle as necessary.
1913:                    for (int i = start; i < limit; i++) {
1914:                        if (wasDash && ch[i] == '-') {
1915:                            writer.write(ch, start, i - start);
1916:                            writer.write(" -");
1917:                            start = i + 1;
1918:                        }
1919:                        wasDash = (ch[i] == '-');
1920:                    }
1921:
1922:                    // if we have some chars in the comment
1923:                    if (length > 0) {
1924:                        // Output the remaining characters (if any)
1925:                        final int remainingChars = (limit - start);
1926:                        if (remainingChars > 0)
1927:                            writer.write(ch, start, remainingChars);
1928:                        // Protect comment end from a single trailing dash
1929:                        if (ch[limit - 1] == '-')
1930:                            writer.write(' ');
1931:                    }
1932:                    writer.write(COMMENT_END);
1933:                } catch (IOException e) {
1934:                    throw new SAXException(e);
1935:                }
1936:
1937:                m_startNewLine = true;
1938:                // time to generate comment event
1939:                if (m_tracer != null)
1940:                    super .fireCommentEvent(ch, start_old, length);
1941:            }
1942:
1943:            /**
1944:             * Report the end of a CDATA section.
1945:             * @throws org.xml.sax.SAXException The application may raise an exception.
1946:             *
1947:             *  @see  #startCDATA
1948:             */
1949:            public void endCDATA() throws org.xml.sax.SAXException {
1950:                if (m_cdataTagOpen)
1951:                    closeCDATA();
1952:                m_cdataStartCalled = false;
1953:            }
1954:
1955:            /**
1956:             * Report the end of DTD declarations.
1957:             * @throws org.xml.sax.SAXException The application may raise an exception.
1958:             * @see #startDTD
1959:             */
1960:            public void endDTD() throws org.xml.sax.SAXException {
1961:                try {
1962:                    if (m_needToOutputDocTypeDecl) {
1963:                        outputDocTypeDecl(m_elemContext.m_elementName, false);
1964:                        m_needToOutputDocTypeDecl = false;
1965:                    }
1966:                    final java.io.Writer writer = m_writer;
1967:                    if (!m_inDoctype)
1968:                        writer.write("]>");
1969:                    else {
1970:                        writer.write('>');
1971:                    }
1972:
1973:                    writer.write(m_lineSep, 0, m_lineSepLen);
1974:                } catch (IOException e) {
1975:                    throw new SAXException(e);
1976:                }
1977:
1978:            }
1979:
1980:            /**
1981:             * End the scope of a prefix-URI Namespace mapping.
1982:             * @see org.xml.sax.ContentHandler#endPrefixMapping
1983:             * 
1984:             * @param prefix The prefix that was being mapping.
1985:             * @throws org.xml.sax.SAXException The client may throw
1986:             *            an exception during processing.
1987:             */
1988:            public void endPrefixMapping(String prefix)
1989:                    throws org.xml.sax.SAXException { // do nothing
1990:            }
1991:
1992:            /**
1993:             * Receive notification of ignorable whitespace in element content.
1994:             * 
1995:             * Not sure how to get this invoked quite yet.
1996:             * 
1997:             * @param ch The characters from the XML document.
1998:             * @param start The start position in the array.
1999:             * @param length The number of characters to read from the array.
2000:             * @throws org.xml.sax.SAXException Any SAX exception, possibly
2001:             *            wrapping another exception.
2002:             * @see #characters
2003:             * 
2004:             * @throws org.xml.sax.SAXException
2005:             */
2006:            public void ignorableWhitespace(char ch[], int start, int length)
2007:                    throws org.xml.sax.SAXException {
2008:
2009:                if (0 == length)
2010:                    return;
2011:                characters(ch, start, length);
2012:            }
2013:
2014:            /**
2015:             * Receive notification of a skipped entity.
2016:             * @see org.xml.sax.ContentHandler#skippedEntity
2017:             * 
2018:             * @param name The name of the skipped entity.  If it is a
2019:             *       parameter                   entity, the name will begin with '%',
2020:             * and if it is the external DTD subset, it will be the string
2021:             * "[dtd]".
2022:             * @throws org.xml.sax.SAXException Any SAX exception, possibly wrapping
2023:             * another exception.
2024:             */
2025:            public void skippedEntity(String name)
2026:                    throws org.xml.sax.SAXException { // TODO: Should handle
2027:            }
2028:
2029:            /**
2030:             * Report the start of a CDATA section.
2031:             * 
2032:             * @throws org.xml.sax.SAXException The application may raise an exception.
2033:             * @see #endCDATA
2034:             */
2035:            public void startCDATA() throws org.xml.sax.SAXException {
2036:                m_cdataStartCalled = true;
2037:            }
2038:
2039:            /**
2040:             * Report the beginning of an entity.
2041:             * 
2042:             * The start and end of the document entity are not reported.
2043:             * The start and end of the external DTD subset are reported
2044:             * using the pseudo-name "[dtd]".  All other events must be
2045:             * properly nested within start/end entity events.
2046:             * 
2047:             * @param name The name of the entity.  If it is a parameter
2048:             *        entity, the name will begin with '%'.
2049:             * @throws org.xml.sax.SAXException The application may raise an exception.
2050:             * @see #endEntity
2051:             * @see org.xml.sax.ext.DeclHandler#internalEntityDecl
2052:             * @see org.xml.sax.ext.DeclHandler#externalEntityDecl
2053:             */
2054:            public void startEntity(String name)
2055:                    throws org.xml.sax.SAXException {
2056:                if (name.equals("[dtd]"))
2057:                    m_inExternalDTD = true;
2058:
2059:                if (!m_expandDTDEntities && !m_inExternalDTD) {
2060:                    /* Only leave the entity as-is if
2061:                     * we've been told not to expand them
2062:                     * and this is not the magic [dtd] name.
2063:                     */
2064:                    startNonEscaping();
2065:                    characters("&" + name + ';');
2066:                    endNonEscaping();
2067:                }
2068:
2069:                m_inEntityRef = true;
2070:            }
2071:
2072:            /**
2073:             * For the enclosing elements starting tag write out
2074:             * out any attributes followed by ">"
2075:             *
2076:             * @throws org.xml.sax.SAXException
2077:             */
2078:            protected void closeStartTag() throws SAXException {
2079:
2080:                if (m_elemContext.m_startTagOpen) {
2081:
2082:                    try {
2083:                        if (m_tracer != null)
2084:                            super .fireStartElem(m_elemContext.m_elementName);
2085:                        int nAttrs = m_attributes.getLength();
2086:                        if (nAttrs > 0) {
2087:                            processAttributes(m_writer, nAttrs);
2088:                            // clear attributes object for re-use with next element
2089:                            m_attributes.clear();
2090:                        }
2091:                        m_writer.write('>');
2092:                    } catch (IOException e) {
2093:                        throw new SAXException(e);
2094:                    }
2095:
2096:                    /* whether Xalan or XSLTC, we have the prefix mappings now, so
2097:                     * lets determine if the current element is specified in the cdata-
2098:                     * section-elements list.
2099:                     */
2100:                    if (m_cdataSectionElements != null)
2101:                        m_elemContext.m_isCdataSection = isCdataSection();
2102:
2103:                    if (m_doIndent) {
2104:                        m_isprevtext = false;
2105:                        m_preserves.push(m_ispreserve);
2106:                    }
2107:                }
2108:
2109:            }
2110:
2111:            /**
2112:             * Report the start of DTD declarations, if any.
2113:             *
2114:             * Any declarations are assumed to be in the internal subset unless
2115:             * otherwise indicated.
2116:             * 
2117:             * @param name The document type name.
2118:             * @param publicId The declared public identifier for the
2119:             *        external DTD subset, or null if none was declared.
2120:             * @param systemId The declared system identifier for the
2121:             *        external DTD subset, or null if none was declared.
2122:             * @throws org.xml.sax.SAXException The application may raise an
2123:             *            exception.
2124:             * @see #endDTD
2125:             * @see #startEntity
2126:             */
2127:            public void startDTD(String name, String publicId, String systemId)
2128:                    throws org.xml.sax.SAXException {
2129:                setDoctypeSystem(systemId);
2130:                setDoctypePublic(publicId);
2131:
2132:                m_elemContext.m_elementName = name;
2133:                m_inDoctype = true;
2134:            }
2135:
2136:            /**
2137:             * Returns the m_indentAmount.
2138:             * @return int
2139:             */
2140:            public int getIndentAmount() {
2141:                return m_indentAmount;
2142:            }
2143:
2144:            /**
2145:             * Sets the m_indentAmount.
2146:             * 
2147:             * @param m_indentAmount The m_indentAmount to set
2148:             */
2149:            public void setIndentAmount(int m_indentAmount) {
2150:                this .m_indentAmount = m_indentAmount;
2151:            }
2152:
2153:            /**
2154:             * Tell if, based on space preservation constraints and the doIndent property,
2155:             * if an indent should occur.
2156:             *
2157:             * @return True if an indent should occur.
2158:             */
2159:            protected boolean shouldIndent() {
2160:                return m_doIndent && (!m_ispreserve && !m_isprevtext);
2161:            }
2162:
2163:            /**
2164:             * Searches for the list of qname properties with the specified key in the
2165:             * property list. If the key is not found in this property list, the default
2166:             * property list, and its defaults, recursively, are then checked. The
2167:             * method returns <code>null</code> if the property is not found.
2168:             *
2169:             * @param   key   the property key.
2170:             * @param props the list of properties to search in.
2171:             * 
2172:             * Sets the vector of local-name/URI pairs of the cdata section elements
2173:             * specified in the cdata-section-elements property.
2174:             * 
2175:             * This method is essentially a copy of getQNameProperties() from
2176:             * OutputProperties. Eventually this method should go away and a call
2177:             * to setCdataSectionElements(Vector v) should be made directly.
2178:             */
2179:            private void setCdataSectionElements(String key, Properties props) {
2180:
2181:                String s = props.getProperty(key);
2182:
2183:                if (null != s) {
2184:                    // Vector of URI/LocalName pairs
2185:                    Vector v = new Vector();
2186:                    int l = s.length();
2187:                    boolean inCurly = false;
2188:                    StringBuffer buf = new StringBuffer();
2189:
2190:                    // parse through string, breaking on whitespaces.  I do this instead
2191:                    // of a tokenizer so I can track whitespace inside of curly brackets,
2192:                    // which theoretically shouldn't happen if they contain legal URLs.
2193:                    for (int i = 0; i < l; i++) {
2194:                        char c = s.charAt(i);
2195:
2196:                        if (Character.isWhitespace(c)) {
2197:                            if (!inCurly) {
2198:                                if (buf.length() > 0) {
2199:                                    addCdataSectionElement(buf.toString(), v);
2200:                                    buf.setLength(0);
2201:                                }
2202:                                continue;
2203:                            }
2204:                        } else if ('{' == c)
2205:                            inCurly = true;
2206:                        else if ('}' == c)
2207:                            inCurly = false;
2208:
2209:                        buf.append(c);
2210:                    }
2211:
2212:                    if (buf.length() > 0) {
2213:                        addCdataSectionElement(buf.toString(), v);
2214:                        buf.setLength(0);
2215:                    }
2216:                    // call the official, public method to set the collected names
2217:                    setCdataSectionElements(v);
2218:                }
2219:
2220:            }
2221:
2222:            /**
2223:             * Adds a URI/LocalName pair of strings to the list.
2224:             *
2225:             * @param URI_and_localName String of the form "{uri}local" or "local" 
2226:             * 
2227:             * @return a QName object
2228:             */
2229:            private void addCdataSectionElement(String URI_and_localName,
2230:                    Vector v) {
2231:
2232:                StringTokenizer tokenizer = new StringTokenizer(
2233:                        URI_and_localName, "{}", false);
2234:                String s1 = tokenizer.nextToken();
2235:                String s2 = tokenizer.hasMoreTokens() ? tokenizer.nextToken()
2236:                        : null;
2237:
2238:                if (null == s2) {
2239:                    // add null URI and the local name
2240:                    v.addElement(null);
2241:                    v.addElement(s1);
2242:                } else {
2243:                    // add URI, then local name
2244:                    v.addElement(s1);
2245:                    v.addElement(s2);
2246:                }
2247:            }
2248:
2249:            /**
2250:             * Remembers the cdata sections specified in the cdata-section-elements.
2251:             * The "official way to set URI and localName pairs. 
2252:             * This method should be used by both Xalan and XSLTC.
2253:             * 
2254:             * @param URI_and_localNames a vector of pairs of Strings (URI/local)
2255:             */
2256:            public void setCdataSectionElements(Vector URI_and_localNames) {
2257:                m_cdataSectionElements = URI_and_localNames;
2258:            }
2259:
2260:            /**
2261:             * Makes sure that the namespace URI for the given qualified attribute name
2262:             * is declared.
2263:             * @param ns the namespace URI
2264:             * @param rawName the qualified name 
2265:             * @return returns null if no action is taken, otherwise it returns the
2266:             * prefix used in declaring the namespace. 
2267:             * @throws SAXException
2268:             */
2269:            protected String ensureAttributesNamespaceIsDeclared(String ns,
2270:                    String localName, String rawName)
2271:                    throws org.xml.sax.SAXException {
2272:
2273:                if (ns != null && ns.length() > 0) {
2274:
2275:                    // extract the prefix in front of the raw name
2276:                    int index = 0;
2277:                    String prefixFromRawName = (index = rawName.indexOf(":")) < 0 ? ""
2278:                            : rawName.substring(0, index);
2279:
2280:                    if (index > 0) {
2281:                        // we have a prefix, lets see if it maps to a namespace 
2282:                        String uri = m_prefixMap
2283:                                .lookupNamespace(prefixFromRawName);
2284:                        if (uri != null && uri.equals(ns)) {
2285:                            // the prefix in the raw name is already maps to the given namespace uri
2286:                            // so we don't need to do anything
2287:                            return null;
2288:                        } else {
2289:                            // The uri does not map to the prefix in the raw name,
2290:                            // so lets make the mapping.
2291:                            this .startPrefixMapping(prefixFromRawName, ns,
2292:                                    false);
2293:                            this .addAttribute("http://www.w3.org/2000/xmlns/",
2294:                                    prefixFromRawName, "xmlns:"
2295:                                            + prefixFromRawName, "CDATA", ns,
2296:                                    false);
2297:                            return prefixFromRawName;
2298:                        }
2299:                    } else {
2300:                        // we don't have a prefix in the raw name.
2301:                        // Does the URI map to a prefix already?
2302:                        String prefix = m_prefixMap.lookupPrefix(ns);
2303:                        if (prefix == null) {
2304:                            // uri is not associated with a prefix,
2305:                            // so lets generate a new prefix to use
2306:                            prefix = m_prefixMap.generateNextPrefix();
2307:                            this .startPrefixMapping(prefix, ns, false);
2308:                            this .addAttribute("http://www.w3.org/2000/xmlns/",
2309:                                    prefix, "xmlns:" + prefix, "CDATA", ns,
2310:                                    false);
2311:                        }
2312:
2313:                        return prefix;
2314:
2315:                    }
2316:                }
2317:                return null;
2318:            }
2319:
2320:            void ensurePrefixIsDeclared(String ns, String rawName)
2321:                    throws org.xml.sax.SAXException {
2322:
2323:                if (ns != null && ns.length() > 0) {
2324:                    int index;
2325:                    final boolean no_prefix = ((index = rawName.indexOf(":")) < 0);
2326:                    String prefix = (no_prefix) ? "" : rawName.substring(0,
2327:                            index);
2328:
2329:                    if (null != prefix) {
2330:                        String foundURI = m_prefixMap.lookupNamespace(prefix);
2331:
2332:                        if ((null == foundURI) || !foundURI.equals(ns)) {
2333:                            this .startPrefixMapping(prefix, ns);
2334:
2335:                            // Bugzilla1133: Generate attribute as well as namespace event.
2336:                            // SAX does expect both.
2337:
2338:                            this .addAttributeAlways(
2339:                                    "http://www.w3.org/2000/xmlns/",
2340:                                    no_prefix ? "xmlns" : prefix, // local name
2341:                                    no_prefix ? "xmlns" : ("xmlns:" + prefix), // qname
2342:                                    "CDATA", ns, false);
2343:                        }
2344:
2345:                    }
2346:                }
2347:            }
2348:
2349:            /**
2350:             * This method flushes any pending events, which can be startDocument()
2351:             * closing the opening tag of an element, or closing an open CDATA section.
2352:             */
2353:            public void flushPending() throws SAXException {
2354:                if (m_needToCallStartDocument) {
2355:                    startDocumentInternal();
2356:                    m_needToCallStartDocument = false;
2357:                }
2358:                if (m_elemContext.m_startTagOpen) {
2359:                    closeStartTag();
2360:                    m_elemContext.m_startTagOpen = false;
2361:                }
2362:
2363:                if (m_cdataTagOpen) {
2364:                    closeCDATA();
2365:                    m_cdataTagOpen = false;
2366:                }
2367:            }
2368:
2369:            public void setContentHandler(ContentHandler ch) {
2370:                // this method is really only useful in the ToSAXHandler classes but it is
2371:                // in the interface.  If the method defined here is ever called
2372:                // we are probably in trouble.
2373:            }
2374:
2375:            /**
2376:             * Adds the given attribute to the set of attributes, even if there is
2377:             * no currently open element. This is useful if a SAX startPrefixMapping()
2378:             * should need to add an attribute before the element name is seen.
2379:             * 
2380:             * This method is a copy of its super classes method, except that some
2381:             * tracing of events is done.  This is so the tracing is only done for
2382:             * stream serializers, not for SAX ones.
2383:             *
2384:             * @param uri the URI of the attribute
2385:             * @param localName the local name of the attribute
2386:             * @param rawName   the qualified name of the attribute
2387:             * @param type the type of the attribute (probably CDATA)
2388:             * @param value the value of the attribute
2389:             * @param xslAttribute true if this attribute is coming from an xsl:attribute element.
2390:             * @return true if the attribute value was added, 
2391:             * false if the attribute already existed and the value was
2392:             * replaced with the new value.
2393:             */
2394:            public boolean addAttributeAlways(String uri, String localName,
2395:                    String rawName, String type, String value,
2396:                    boolean xslAttribute) {
2397:                boolean was_added;
2398:                int index;
2399:                if (uri == null || localName == null || uri.length() == 0)
2400:                    index = m_attributes.getIndex(rawName);
2401:                else {
2402:                    index = m_attributes.getIndex(uri, localName);
2403:                }
2404:
2405:                if (index >= 0) {
2406:                    String old_value = null;
2407:                    if (m_tracer != null) {
2408:                        old_value = m_attributes.getValue(index);
2409:                        if (value.equals(old_value))
2410:                            old_value = null;
2411:                    }
2412:
2413:                    /* We've seen the attribute before.
2414:                     * We may have a null uri or localName, but all we really
2415:                     * want to re-set is the value anyway.
2416:                     */
2417:                    m_attributes.setValue(index, value);
2418:                    was_added = false;
2419:                    if (old_value != null)
2420:                        firePseudoAttributes();
2421:
2422:                } else {
2423:                    // the attribute doesn't exist yet, create it
2424:                    if (xslAttribute) {
2425:                        /*
2426:                         * This attribute is from an xsl:attribute element so we take some care in
2427:                         * adding it, e.g.
2428:                         *   <elem1  foo:attr1="1" xmlns:foo="uri1">
2429:                         *       <xsl:attribute name="foo:attr2">2</xsl:attribute>
2430:                         *   </elem1>
2431:                         * 
2432:                         * We are adding attr1 and attr2 both as attributes of elem1,
2433:                         * and this code is adding attr2 (the xsl:attribute ).
2434:                         * We could have a collision with the prefix like in the example above.
2435:                         */
2436:
2437:                        // In the example above, is there a prefix like foo ?
2438:                        final int colonIndex = rawName.indexOf(':');
2439:                        if (colonIndex > 0) {
2440:                            String prefix = rawName.substring(0, colonIndex);
2441:                            NamespaceMappings.MappingRecord existing_mapping = m_prefixMap
2442:                                    .getMappingFromPrefix(prefix);
2443:
2444:                            /* Before adding this attribute (foo:attr2),
2445:                             * is the prefix for it (foo) already mapped at the current depth?
2446:                             */
2447:                            if (existing_mapping != null
2448:                                    && existing_mapping.m_declarationDepth == m_elemContext.m_currentElemDepth
2449:                                    && !existing_mapping.m_uri.equals(uri)) {
2450:                                /*
2451:                                 * There is an existing mapping of this prefix,
2452:                                 * it differs from the one we need,
2453:                                 * and unfortunately it is at the current depth so we 
2454:                                 * can not over-ride it.
2455:                                 */
2456:
2457:                                /*
2458:                                 * Are we lucky enough that an existing other prefix maps to this URI ?
2459:                                 */
2460:                                prefix = m_prefixMap.lookupPrefix(uri);
2461:                                if (prefix == null) {
2462:                                    /* Unfortunately there is no existing prefix that happens to map to ours,
2463:                                     * so to avoid a prefix collision we must generated a new prefix to use. 
2464:                                     * This is OK because the prefix URI mapping
2465:                                     * defined in the xsl:attribute is short in scope, 
2466:                                     * just the xsl:attribute element itself, 
2467:                                     * and at this point in serialization the body of the
2468:                                     * xsl:attribute, if any, is just a String. Right?
2469:                                     *   . . . I sure hope so - Brian M. 
2470:                                     */
2471:                                    prefix = m_prefixMap.generateNextPrefix();
2472:                                }
2473:
2474:                                rawName = prefix + ':' + localName;
2475:                            }
2476:                        }
2477:
2478:                        try {
2479:                            /* This is our last chance to make sure the namespace for this
2480:                             * attribute is declared, especially if we just generated an alternate
2481:                             * prefix to avoid a collision (the new prefix/rawName will go out of scope
2482:                             * soon and be lost ...  last chance here.
2483:                             */
2484:                            String prefixUsed = ensureAttributesNamespaceIsDeclared(
2485:                                    uri, localName, rawName);
2486:                        } catch (SAXException e) {
2487:                            // TODO Auto-generated catch block
2488:                            e.printStackTrace();
2489:                        }
2490:                    }
2491:                    m_attributes.addAttribute(uri, localName, rawName, type,
2492:                            value);
2493:                    was_added = true;
2494:                    if (m_tracer != null)
2495:                        firePseudoAttributes();
2496:                }
2497:                return was_added;
2498:            }
2499:
2500:            /**
2501:             * To fire off the pseudo characters of attributes, as they currently
2502:             * exist. This method should be called everytime an attribute is added,
2503:             * or when an attribute value is changed, or an element is created.
2504:             */
2505:
2506:            protected void firePseudoAttributes() {
2507:                if (m_tracer != null) {
2508:                    try {
2509:                        // flush out the "<elemName" if not already flushed
2510:                        m_writer.flush();
2511:
2512:                        // make a StringBuffer to write the name="value" pairs to.
2513:                        StringBuffer sb = new StringBuffer();
2514:                        int nAttrs = m_attributes.getLength();
2515:                        if (nAttrs > 0) {
2516:                            // make a writer that internally appends to the same
2517:                            // StringBuffer
2518:                            java.io.Writer writer = new ToStream.WritertoStringBuffer(
2519:                                    sb);
2520:
2521:                            processAttributes(writer, nAttrs);
2522:                            // Don't clear the attributes! 
2523:                            // We only want to see what would be written out
2524:                            // at this point, we don't want to loose them.
2525:                        }
2526:                        sb.append('>'); // the potential > after the attributes.
2527:                        // convert the StringBuffer to a char array and
2528:                        // emit the trace event that these characters "might"
2529:                        // be written                
2530:                        char ch[] = sb.toString().toCharArray();
2531:                        m_tracer
2532:                                .fireGenerateEvent(
2533:                                        SerializerTrace.EVENTTYPE_OUTPUT_PSEUDO_CHARACTERS,
2534:                                        ch, 0, ch.length);
2535:                    } catch (IOException ioe) {
2536:                        // ignore ?
2537:                    } catch (SAXException se) {
2538:                        // ignore ?
2539:                    }
2540:                }
2541:            }
2542:
2543:            /**
2544:             * This inner class is used only to collect attribute values
2545:             * written by the method writeAttrString() into a string buffer.
2546:             * In this manner trace events, and the real writing of attributes will use
2547:             * the same code.
2548:             */
2549:            private class WritertoStringBuffer extends java.io.Writer {
2550:                final private StringBuffer m_stringbuf;
2551:
2552:                /**
2553:                 * @see java.io.Writer#write(char[], int, int)
2554:                 */
2555:                WritertoStringBuffer(StringBuffer sb) {
2556:                    m_stringbuf = sb;
2557:                }
2558:
2559:                public void write(char[] arg0, int arg1, int arg2)
2560:                        throws IOException {
2561:                    m_stringbuf.append(arg0, arg1, arg2);
2562:                }
2563:
2564:                /**
2565:                 * @see java.io.Writer#flush()
2566:                 */
2567:                public void flush() throws IOException {
2568:                }
2569:
2570:                /**
2571:                 * @see java.io.Writer#close()
2572:                 */
2573:                public void close() throws IOException {
2574:                }
2575:
2576:                public void write(int i) {
2577:                    m_stringbuf.append((char) i);
2578:                }
2579:
2580:                public void write(String s) {
2581:                    m_stringbuf.append(s);
2582:                }
2583:            }
2584:
2585:            /**
2586:             * @see SerializationHandler#setTransformer(Transformer)
2587:             */
2588:            public void setTransformer(Transformer transformer) {
2589:                super .setTransformer(transformer);
2590:                if (m_tracer != null
2591:                        && !(m_writer instanceof  SerializerTraceWriter))
2592:                    m_writer = new SerializerTraceWriter(m_writer, m_tracer);
2593:
2594:            }
2595:
2596:            /**
2597:             * Try's to reset the super class and reset this class for 
2598:             * re-use, so that you don't need to create a new serializer 
2599:             * (mostly for performance reasons).
2600:             * 
2601:             * @return true if the class was successfuly reset.
2602:             */
2603:            public boolean reset() {
2604:                boolean wasReset = false;
2605:                if (super .reset()) {
2606:                    resetToStream();
2607:                    wasReset = true;
2608:                }
2609:                return wasReset;
2610:            }
2611:
2612:            /**
2613:             * Reset all of the fields owned by ToStream class
2614:             *
2615:             */
2616:            private void resetToStream() {
2617:                this .m_cdataStartCalled = false;
2618:                /* The stream is being reset. It is one of
2619:                 * ToXMLStream, ToHTMLStream ... and this type can't be changed
2620:                 * so neither should m_charInfo which is associated with the
2621:                 * type of Stream. Just leave m_charInfo as-is for the next re-use.
2622:                 * 
2623:                 */
2624:                // this.m_charInfo = null; // don't set to null 
2625:                this .m_disableOutputEscapingStates.clear();
2626:
2627:                this .m_escaping = true;
2628:                // Leave m_format alone for now - Brian M.
2629:                // this.m_format = null;
2630:                this .m_inDoctype = false;
2631:                this .m_ispreserve = false;
2632:                this .m_ispreserve = false;
2633:                this .m_isprevtext = false;
2634:                this .m_isUTF8 = false; //  ?? used anywhere ??
2635:                this .m_preserves.clear();
2636:                this .m_shouldFlush = true;
2637:                this .m_spaceBeforeClose = false;
2638:                this .m_startNewLine = false;
2639:                this .m_lineSepUse = true;
2640:                // DON'T SET THE WRITER TO NULL, IT MAY BE REUSED !!
2641:                // this.m_writer = null;  
2642:                this .m_expandDTDEntities = true;
2643:
2644:            }
2645:
2646:            /**
2647:             * Sets the character encoding coming from the xsl:output encoding stylesheet attribute.
2648:             * @param encoding the character encoding
2649:             */
2650:            public void setEncoding(String encoding) {
2651:                String old = getEncoding();
2652:                super .setEncoding(encoding);
2653:                if (old == null || !old.equals(encoding)) {
2654:                    // If we have changed the setting of the 
2655:                    m_encodingInfo = Encodings.getEncodingInfo(encoding);
2656:
2657:                    if (encoding != null && m_encodingInfo.name == null) {
2658:                        // We tried to get an EncodingInfo for Object for the given
2659:                        // encoding, but it came back with an internall null name
2660:                        // so the encoding is not supported by the JDK, issue a message.
2661:                        String msg = Utils.messages.createMessage(
2662:                                MsgKey.ER_ENCODING_NOT_SUPPORTED,
2663:                                new Object[] { encoding });
2664:                        try {
2665:                            // Prepare to issue the warning message
2666:                            Transformer tran = super .getTransformer();
2667:                            if (tran != null) {
2668:                                ErrorListener errHandler = tran
2669:                                        .getErrorListener();
2670:                                // Issue the warning message
2671:                                if (null != errHandler
2672:                                        && m_sourceLocator != null)
2673:                                    errHandler
2674:                                            .warning(new TransformerException(
2675:                                                    msg, m_sourceLocator));
2676:                                else
2677:                                    System.out.println(msg);
2678:                            } else
2679:                                System.out.println(msg);
2680:                        } catch (Exception e) {
2681:                        }
2682:                    }
2683:                }
2684:                return;
2685:            }
2686:
2687:            /**
2688:             * Simple stack for boolean values.
2689:             * 
2690:             * This class is a copy of the one in org.apache.xml.utils. 
2691:             * It exists to cut the serializers dependancy on that package.
2692:             * A minor changes from that package are:
2693:             * doesn't implement Clonable
2694:             *  
2695:             * @xsl.usage internal
2696:             */
2697:            static final class BoolStack {
2698:
2699:                /** Array of boolean values          */
2700:                private boolean m_values[];
2701:
2702:                /** Array size allocated           */
2703:                private int m_allocatedSize;
2704:
2705:                /** Index into the array of booleans          */
2706:                private int m_index;
2707:
2708:                /**
2709:                 * Default constructor.  Note that the default
2710:                 * block size is very small, for small lists.
2711:                 */
2712:                public BoolStack() {
2713:                    this (32);
2714:                }
2715:
2716:                /**
2717:                 * Construct a IntVector, using the given block size.
2718:                 *
2719:                 * @param size array size to allocate
2720:                 */
2721:                public BoolStack(int size) {
2722:
2723:                    m_allocatedSize = size;
2724:                    m_values = new boolean[size];
2725:                    m_index = -1;
2726:                }
2727:
2728:                /**
2729:                 * Get the length of the list.
2730:                 *
2731:                 * @return Current length of the list
2732:                 */
2733:                public final int size() {
2734:                    return m_index + 1;
2735:                }
2736:
2737:                /**
2738:                 * Clears the stack.
2739:                 *
2740:                 */
2741:                public final void clear() {
2742:                    m_index = -1;
2743:                }
2744:
2745:                /**
2746:                 * Pushes an item onto the top of this stack.
2747:                 *
2748:                 *
2749:                 * @param val the boolean to be pushed onto this stack.
2750:                 * @return  the <code>item</code> argument.
2751:                 */
2752:                public final boolean push(boolean val) {
2753:
2754:                    if (m_index == m_allocatedSize - 1)
2755:                        grow();
2756:
2757:                    return (m_values[++m_index] = val);
2758:                }
2759:
2760:                /**
2761:                 * Removes the object at the top of this stack and returns that
2762:                 * object as the value of this function.
2763:                 *
2764:                 * @return     The object at the top of this stack.
2765:                 * @throws  EmptyStackException  if this stack is empty.
2766:                 */
2767:                public final boolean pop() {
2768:                    return m_values[m_index--];
2769:                }
2770:
2771:                /**
2772:                 * Removes the object at the top of this stack and returns the
2773:                 * next object at the top as the value of this function.
2774:                 *
2775:                 *
2776:                 * @return Next object to the top or false if none there
2777:                 */
2778:                public final boolean popAndTop() {
2779:
2780:                    m_index--;
2781:
2782:                    return (m_index >= 0) ? m_values[m_index] : false;
2783:                }
2784:
2785:                /**
2786:                 * Set the item at the top of this stack  
2787:                 *
2788:                 *
2789:                 * @param b Object to set at the top of this stack
2790:                 */
2791:                public final void setTop(boolean b) {
2792:                    m_values[m_index] = b;
2793:                }
2794:
2795:                /**
2796:                 * Looks at the object at the top of this stack without removing it
2797:                 * from the stack.
2798:                 *
2799:                 * @return     the object at the top of this stack.
2800:                 * @throws  EmptyStackException  if this stack is empty.
2801:                 */
2802:                public final boolean peek() {
2803:                    return m_values[m_index];
2804:                }
2805:
2806:                /**
2807:                 * Looks at the object at the top of this stack without removing it
2808:                 * from the stack.  If the stack is empty, it returns false.
2809:                 *
2810:                 * @return     the object at the top of this stack.
2811:                 */
2812:                public final boolean peekOrFalse() {
2813:                    return (m_index > -1) ? m_values[m_index] : false;
2814:                }
2815:
2816:                /**
2817:                 * Looks at the object at the top of this stack without removing it
2818:                 * from the stack.  If the stack is empty, it returns true.
2819:                 *
2820:                 * @return     the object at the top of this stack.
2821:                 */
2822:                public final boolean peekOrTrue() {
2823:                    return (m_index > -1) ? m_values[m_index] : true;
2824:                }
2825:
2826:                /**
2827:                 * Tests if this stack is empty.
2828:                 *
2829:                 * @return  <code>true</code> if this stack is empty;
2830:                 *          <code>false</code> otherwise.
2831:                 */
2832:                public boolean isEmpty() {
2833:                    return (m_index == -1);
2834:                }
2835:
2836:                /**
2837:                 * Grows the size of the stack
2838:                 *
2839:                 */
2840:                private void grow() {
2841:
2842:                    m_allocatedSize *= 2;
2843:
2844:                    boolean newVector[] = new boolean[m_allocatedSize];
2845:
2846:                    System.arraycopy(m_values, 0, newVector, 0, m_index + 1);
2847:
2848:                    m_values = newVector;
2849:                }
2850:            }
2851:
2852:            // Implement DTDHandler
2853:            /**
2854:             * If this method is called, the serializer is used as a
2855:             * DTDHandler, which changes behavior how the serializer 
2856:             * handles document entities. 
2857:             * @see org.xml.sax.DTDHandler#notationDecl(java.lang.String, java.lang.String, java.lang.String)
2858:             */
2859:            public void notationDecl(String name, String pubID, String sysID)
2860:                    throws SAXException {
2861:                // TODO Auto-generated method stub
2862:                try {
2863:                    DTDprolog();
2864:
2865:                    m_writer.write("<!NOTATION ");
2866:                    m_writer.write(name);
2867:                    if (pubID != null) {
2868:                        m_writer.write(" PUBLIC \"");
2869:                        m_writer.write(pubID);
2870:
2871:                    } else {
2872:                        m_writer.write(" SYSTEM \"");
2873:                        m_writer.write(sysID);
2874:                    }
2875:                    m_writer.write("\" >");
2876:                    m_writer.write(m_lineSep, 0, m_lineSepLen);
2877:                } catch (IOException e) {
2878:                    // TODO Auto-generated catch block
2879:                    e.printStackTrace();
2880:                }
2881:            }
2882:
2883:            /**
2884:             * If this method is called, the serializer is used as a
2885:             * DTDHandler, which changes behavior how the serializer 
2886:             * handles document entities. 
2887:             * @see org.xml.sax.DTDHandler#unparsedEntityDecl(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
2888:             */
2889:            public void unparsedEntityDecl(String name, String pubID,
2890:                    String sysID, String notationName) throws SAXException {
2891:                // TODO Auto-generated method stub
2892:                try {
2893:                    DTDprolog();
2894:
2895:                    m_writer.write("<!ENTITY ");
2896:                    m_writer.write(name);
2897:                    if (pubID != null) {
2898:                        m_writer.write(" PUBLIC \"");
2899:                        m_writer.write(pubID);
2900:
2901:                    } else {
2902:                        m_writer.write(" SYSTEM \"");
2903:                        m_writer.write(sysID);
2904:                    }
2905:                    m_writer.write("\" NDATA ");
2906:                    m_writer.write(notationName);
2907:                    m_writer.write(" >");
2908:                    m_writer.write(m_lineSep, 0, m_lineSepLen);
2909:                } catch (IOException e) {
2910:                    // TODO Auto-generated catch block
2911:                    e.printStackTrace();
2912:                }
2913:            }
2914:
2915:            /**
2916:             * A private helper method to output the 
2917:             * @throws SAXException
2918:             * @throws IOException
2919:             */
2920:            private void DTDprolog() throws SAXException, IOException {
2921:                final java.io.Writer writer = m_writer;
2922:                if (m_needToOutputDocTypeDecl) {
2923:                    outputDocTypeDecl(m_elemContext.m_elementName, false);
2924:                    m_needToOutputDocTypeDecl = false;
2925:                }
2926:                if (m_inDoctype) {
2927:                    writer.write(" [");
2928:                    writer.write(m_lineSep, 0, m_lineSepLen);
2929:                    m_inDoctype = false;
2930:                }
2931:            }
2932:
2933:            /**
2934:             * If set to false the serializer does not expand DTD entities,
2935:             * but leaves them as is, the default value is true;
2936:             */
2937:            public void setDTDEntityExpansion(boolean expand) {
2938:                m_expandDTDEntities = expand;
2939:            }
2940:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.