19f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/*
29f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Licensed to the Apache Software Foundation (ASF) under one
39f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * or more contributor license agreements. See the NOTICE file
49f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * distributed with this work for additional information
59f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * regarding copyright ownership. The ASF licenses this file
69f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * to you under the Apache License, Version 2.0 (the  "License");
79f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * you may not use this file except in compliance with the License.
89f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * You may obtain a copy of the License at
99f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *     http://www.apache.org/licenses/LICENSE-2.0
119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Unless required by applicable law or agreed to in writing, software
139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * See the License for the specific language governing permissions and
169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * limitations under the License.
179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */
189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/*
199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * $Id: SerializerTraceWriter.java 468654 2006-10-28 07:09:23Z minchau $
209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */
219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonpackage org.apache.xml.serializer;
229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport java.io.IOException;
249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport java.io.OutputStream;
259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport java.io.Writer;
269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/**
289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * This class wraps the real writer, it only purpose is to send
299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * CHARACTERTOSTREAM events to the trace listener.
309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Each method immediately sends the call to the wrapped writer unchanged, but
319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * in addition it collects characters to be issued to a trace listener.
329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * In this way the trace
349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * listener knows what characters have been written to the output Writer.
359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * There may still be differences in what the trace events say is going to the
379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * output writer and what is really going there. These differences will be due
389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * to the fact that this class is UTF-8 encoding before emiting the trace event
399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * and the underlying writer may not be UTF-8 encoding. There may also be
409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * encoding differences.  So the main pupose of this class is to provide a
419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * resonable facsimile of the true output.
429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @xsl.usage internal
449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */
459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonfinal class SerializerTraceWriter extends Writer implements WriterChain
469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /** The real writer to immediately write to.
499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * This reference may be null, in which case nothing is written out, but
509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * only the trace events are fired for output.
519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    private final java.io.Writer m_writer;
539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /** The tracer to send events to */
559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    private final SerializerTrace m_tracer;
569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /** The size of the internal buffer, just to keep too many
589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * events from being sent to the tracer
599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    private int buf_length;
619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Internal buffer to collect the characters to go to the trace listener.
649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     *
659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    private byte buf[];
679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * How many bytes have been collected and still need to go to trace
709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * listener.
719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    private int count;
739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Creates or replaces the internal buffer, and makes sure it has a few
769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * extra bytes slight overflow of the last UTF8 encoded character.
779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @param size
789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    private void setBufferSize(int size)
809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        buf = new byte[size + 3];
829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        buf_length = size;
839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        count = 0;
849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Constructor.
889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * If the writer passed in is null, then this SerializerTraceWriter will
899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * only signal trace events of what would have been written to that writer.
909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * If the writer passed in is not null then the trace events will mirror
919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * what is going to that writer. In this way tools, such as a debugger, can
929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * gather information on what is being written out.
939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     *
949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @param out the Writer to write to (possibly null)
959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @param tracer the tracer to inform that characters are being written
969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    public SerializerTraceWriter(Writer out, SerializerTrace tracer)
989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        m_writer = out;
1009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        m_tracer = tracer;
1019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        setBufferSize(1024);
1029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
1059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Flush out the collected characters by sending them to the trace
1069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * listener.  These characters are never written to the real writer
1079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * (m_writer) because that has already happened with every method
1089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * call. This method simple informs the listener of what has already
1099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * happened.
1109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @throws IOException
1119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
1129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    private void flushBuffer() throws IOException
1139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
1149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // Just for tracing purposes
1169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (count > 0)
1179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
1189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            char[] chars = new char[count];
1199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            for(int i=0; i<count; i++)
1209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                chars[i] = (char) buf[i];
1219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            if (m_tracer != null)
1239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                m_tracer.fireGenerateEvent(
1249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                    SerializerTrace.EVENTTYPE_OUTPUT_CHARACTERS,
1259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                    chars,
1269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                    0,
1279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                    chars.length);
1289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            count = 0;
1309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
1319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
1349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Flush the internal buffer and flush the Writer
1359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @see java.io.Writer#flush()
1369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
1379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    public void flush() throws java.io.IOException
1389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
1399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // send to the real writer
1409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (m_writer != null)
1419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            m_writer.flush();
1429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // from here on just for tracing purposes
1449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        flushBuffer();
1459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
1489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Flush the internal buffer and close the Writer
1499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @see java.io.Writer#close()
1509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
1519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    public void close() throws java.io.IOException
1529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
1539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // send to the real writer
1549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (m_writer != null)
1559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            m_writer.close();
1569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // from here on just for tracing purposes
1589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        flushBuffer();
1599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
1639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Write a single character.  The character to be written is contained in
1649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * the 16 low-order bits of the given integer value; the 16 high-order bits
1659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * are ignored.
1669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     *
1679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * <p> Subclasses that intend to support efficient single-character output
1689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * should override this method.
1699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     *
1709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @param c  int specifying a character to be written.
1719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @exception  IOException  If an I/O error occurs
1729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
1739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    public void write(final int c) throws IOException
1749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
1759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // send to the real writer
1769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (m_writer != null)
1779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            m_writer.write(c);
1789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // ---------- from here on just collect for tracing purposes
1809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        /* If we are close to the end of the buffer then flush it.
1829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         * Remember the buffer can hold a few more characters than buf_length
1839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         */
1849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (count >= buf_length)
1859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            flushBuffer();
1869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (c < 0x80)
1889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
1899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            buf[count++] = (byte) (c);
1909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
1919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        else if (c < 0x800)
1929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
1939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            buf[count++] = (byte) (0xc0 + (c >> 6));
1949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            buf[count++] = (byte) (0x80 + (c & 0x3f));
1959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
1969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        else
1979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
1989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            buf[count++] = (byte) (0xe0 + (c >> 12));
1999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            buf[count++] = (byte) (0x80 + ((c >> 6) & 0x3f));
2009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            buf[count++] = (byte) (0x80 + (c & 0x3f));
2019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
2029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
2039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
2059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Write a portion of an array of characters.
2069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     *
2079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @param  chars  Array of characters
2089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @param  start   Offset from which to start writing characters
2099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @param  length   Number of characters to write
2109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     *
2119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @exception  IOException  If an I/O error occurs
2129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     *
2139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @throws java.io.IOException
2149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
2159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    public void write(final char chars[], final int start, final int length)
2169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        throws java.io.IOException
2179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
2189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // send to the real writer
2199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (m_writer != null)
2209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            m_writer.write(chars, start, length);
2219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // from here on just collect for tracing purposes
2239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        int lengthx3 = (length << 1) + length;
2249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (lengthx3 >= buf_length)
2269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
2279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            /* If the request length exceeds the size of the output buffer,
2299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson              * flush the output buffer and make the buffer bigger to handle.
2309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson              */
2319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            flushBuffer();
2339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            setBufferSize(2 * lengthx3);
2349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
2369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (lengthx3 > buf_length - count)
2389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
2399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            flushBuffer();
2409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
2419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        final int n = length + start;
2439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        for (int i = start; i < n; i++)
2449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
2459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            final char c = chars[i];
2469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            if (c < 0x80)
2489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                buf[count++] = (byte) (c);
2499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            else if (c < 0x800)
2509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            {
2519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                buf[count++] = (byte) (0xc0 + (c >> 6));
2529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                buf[count++] = (byte) (0x80 + (c & 0x3f));
2539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            }
2549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            else
2559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            {
2569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                buf[count++] = (byte) (0xe0 + (c >> 12));
2579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                buf[count++] = (byte) (0x80 + ((c >> 6) & 0x3f));
2589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                buf[count++] = (byte) (0x80 + (c & 0x3f));
2599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            }
2609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
2619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
2639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
2659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Write a string.
2669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     *
2679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @param  s  String to be written
2689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     *
2699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * @exception  IOException  If an I/O error occurs
2709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
2719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    public void write(final String s) throws IOException
2729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
2739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // send to the real writer
2749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (m_writer != null)
2759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            m_writer.write(s);
2769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // from here on just collect for tracing purposes
2789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        final int length = s.length();
2799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // We multiply the length by three since this is the maximum length
2819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // of the characters that we can put into the buffer.  It is possible
2829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        // for each Unicode character to expand to three bytes.
2839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        int lengthx3 = (length << 1) + length;
2859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (lengthx3 >= buf_length)
2879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
2889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            /* If the request length exceeds the size of the output buffer,
2909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson              * flush the output buffer and make the buffer bigger to handle.
2919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson              */
2929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            flushBuffer();
2949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            setBufferSize(2 * lengthx3);
2959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
2969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (lengthx3 > buf_length - count)
2989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
2999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            flushBuffer();
3009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
3019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        for (int i = 0; i < length; i++)
3039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
3049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            final char c = s.charAt(i);
3059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            if (c < 0x80)
3079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                buf[count++] = (byte) (c);
3089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            else if (c < 0x800)
3099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            {
3109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                buf[count++] = (byte) (0xc0 + (c >> 6));
3119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                buf[count++] = (byte) (0x80 + (c & 0x3f));
3129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            }
3139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            else
3149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            {
3159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                buf[count++] = (byte) (0xe0 + (c >> 12));
3169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                buf[count++] = (byte) (0x80 + ((c >> 6) & 0x3f));
3179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                buf[count++] = (byte) (0x80 + (c & 0x3f));
3189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            }
3199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
3209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
3219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
3239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Get the writer that this one directly wraps.
3249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
3259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    public Writer getWriter()
3269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
3279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        return m_writer;
3289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
3299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
3319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Get the OutputStream that is the at the end of the
3329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * chain of writers.
3339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
3349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    public OutputStream getOutputStream()
3359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
3369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        OutputStream retval = null;
3379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (m_writer instanceof WriterChain)
3389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            retval = ((WriterChain) m_writer).getOutputStream();
3399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        return retval;
3409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
3419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
342