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: WriterToUTF8Buffered.java 469356 2006-10-31 03:20:34Z 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.UnsupportedEncodingException;
269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport java.io.Writer;
279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/**
309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * This class writes unicode characters to a byte stream (java.io.OutputStream)
319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * as quickly as possible. It buffers the output in an internal
329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * buffer which must be flushed to the OutputStream when done. This flushing
339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * is done via the close() flush() or flushBuffer() method.
349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * This class is only used internally within Xalan.
369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @xsl.usage internal
389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */
399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonfinal class WriterToUTF8Buffered extends Writer implements WriterChain
409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /** number of bytes that the byte buffer can hold.
439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * This is a fixed constant is used rather than m_outputBytes.lenght for performance.
449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private static final int BYTES_MAX=16*1024;
469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /** number of characters that the character buffer can hold.
479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * This is 1/3 of the number of bytes because UTF-8 encoding
489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * can expand one unicode character by up to 3 bytes.
499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private static final int CHARS_MAX=(BYTES_MAX/3);
519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson // private static final int
539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /** The byte stream to write to. (sc & sb remove final to compile in JDK 1.1.8) */
559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private final OutputStream m_os;
569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * The internal buffer where data is stored.
599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * (sc & sb remove final to compile in JDK 1.1.8)
609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private final byte m_outputBytes[];
629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private final char m_inputChars[];
649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * The number of valid bytes in the buffer. This value is always
679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * in the range <tt>0</tt> through <tt>m_outputBytes.length</tt>; elements
689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * <tt>m_outputBytes[0]</tt> through <tt>m_outputBytes[count-1]</tt> contain valid
699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * byte data.
709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private int count;
729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Create an buffered UTF-8 writer.
759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param   out    the underlying output stream.
789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @throws UnsupportedEncodingException
809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public WriterToUTF8Buffered(OutputStream out)
829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      m_os = out;
849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // get 3 extra bytes to make buffer overflow checking simpler and faster
859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // we won't have to keep checking for a few extra characters
869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      m_outputBytes = new byte[BYTES_MAX + 3];
879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // Big enough to hold the input chars that will be transformed
899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // into output bytes in m_ouputBytes.
909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      m_inputChars = new char[CHARS_MAX + 2];
919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      count = 0;
929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson//      the old body of this constructor, before the buffersize was changed to a constant
949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson//      this(out, 8*1024);
959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Create an buffered UTF-8 writer to write data to the
999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * specified underlying output stream with the specified buffer
1009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * size.
1019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
1029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param   out    the underlying output stream.
1039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param   size   the buffer size.
1049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @exception IllegalArgumentException if size <= 0.
1059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
1069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson//  public WriterToUTF8Buffered(final OutputStream out, final int size)
1079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson//  {
1089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson//
1099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson//    m_os = out;
1109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson//
1119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson//    if (size <= 0)
1129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson//    {
1139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson//      throw new IllegalArgumentException(
1149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson//        SerializerMessages.createMessage(SerializerErrorResources.ER_BUFFER_SIZE_LESSTHAN_ZERO, null)); //"Buffer size <= 0");
1159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson//    }
1169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson//
1179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson//    m_outputBytes = new byte[size];
1189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson//    count = 0;
1199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson//  }
1209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
1229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Write a single character.  The character to be written is contained in
1239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * the 16 low-order bits of the given integer value; the 16 high-order bits
1249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * are ignored.
1259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
1269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * <p> Subclasses that intend to support efficient single-character output
1279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * should override this method.
1289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
1299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param c  int specifying a character to be written.
1309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @exception  IOException  If an I/O error occurs
1319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
1329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void write(final int c) throws IOException
1339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
1349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /* If we are close to the end of the buffer then flush it.
1369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     * Remember the buffer can hold a few more bytes than BYTES_MAX
1379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     */
1389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if (count >= BYTES_MAX)
1399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        flushBuffer();
1409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if (c < 0x80)
1429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
1439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       m_outputBytes[count++] = (byte) (c);
1449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    else if (c < 0x800)
1469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
1479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      m_outputBytes[count++] = (byte) (0xc0 + (c >> 6));
1489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      m_outputBytes[count++] = (byte) (0x80 + (c & 0x3f));
1499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    else if (c < 0x10000)
1519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
1529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      m_outputBytes[count++] = (byte) (0xe0 + (c >> 12));
1539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      m_outputBytes[count++] = (byte) (0x80 + ((c >> 6) & 0x3f));
1549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      m_outputBytes[count++] = (byte) (0x80 + (c & 0x3f));
1559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	else
1579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	{
1589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	  m_outputBytes[count++] = (byte) (0xf0 + (c >> 18));
1599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	  m_outputBytes[count++] = (byte) (0x80 + ((c >> 12) & 0x3f));
1609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	  m_outputBytes[count++] = (byte) (0x80 + ((c >> 6) & 0x3f));
1619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	  m_outputBytes[count++] = (byte) (0x80 + (c & 0x3f));
1629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson	}
1639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
1659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
1689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Write a portion of an array of characters.
1699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
1709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param  chars  Array of characters
1719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param  start   Offset from which to start writing characters
1729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param  length   Number of characters to write
1739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
1749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @exception  IOException  If an I/O error occurs
1759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
1769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @throws java.io.IOException
1779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
1789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void write(final char chars[], final int start, final int length)
1799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          throws java.io.IOException
1809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
1819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // We multiply the length by three since this is the maximum length
1839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // of the characters that we can put into the buffer.  It is possible
1849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // for each Unicode character to expand to three bytes.
1859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    int lengthx3 = 3*length;
1879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if (lengthx3 >= BYTES_MAX - count)
1899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
1909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // The requested length is greater than the unused part of the buffer
1919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      flushBuffer();
1929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if (lengthx3 > BYTES_MAX)
1949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
1959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        /*
1969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         * The requested length exceeds the size of the buffer.
1979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         * Cut the buffer up into chunks, each of which will
1989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         * not cause an overflow to the output buffer m_outputBytes,
1999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         * and make multiple recursive calls.
2009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         * Be careful about integer overflows in multiplication.
2019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         */
2029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        int split = length/CHARS_MAX;
2039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        final int chunks;
2049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        if (length % CHARS_MAX > 0)
2059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            chunks = split + 1;
2069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        else
2079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            chunks = split;
2089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        int end_chunk = start;
2099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        for (int chunk = 1; chunk <= chunks; chunk++)
2109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
2119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            int start_chunk = end_chunk;
2129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            end_chunk = start + (int) ((((long) length) * chunk) / chunks);
2139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            // Adjust the end of the chunk if it ends on a high char
2159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            // of a Unicode surrogate pair and low char of the pair
2169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            // is not going to be in the same chunk
2179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            final char c = chars[end_chunk - 1];
2189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            int ic = chars[end_chunk - 1];
2199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            if (c >= 0xD800 && c <= 0xDBFF) {
2209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // The last Java char that we were going
2219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // to process is the first of a
2229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // Java surrogate char pair that
2239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                // represent a Unicode character.
2249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                if (end_chunk < start + length) {
2269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                    // Avoid spanning by including the low
2279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                    // char in the current chunk of chars.
2289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                    end_chunk++;
2299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                } else {
2309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                    /* This is the last char of the last chunk,
2319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                     * and it is the high char of a high/low pair with
2329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                     * no low char provided.
2339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                     * TODO: error message needed.
2349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                     * The char array incorrectly ends in a high char
2359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                     * of a high/low surrogate pair, but there is
2369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                     * no corresponding low as the high is the last char
2379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                     */
2389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                    end_chunk--;
2399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                }
2409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            }
2419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            int len_chunk = (end_chunk - start_chunk);
2449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            this.write(chars,start_chunk, len_chunk);
2459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
2469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        return;
2479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
2489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
2499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    final int n = length+start;
2539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    final byte[] buf_loc = m_outputBytes; // local reference for faster access
2549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    int count_loc = count;      // local integer for faster access
2559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    int i = start;
2569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
2579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        /* This block could be omitted and the code would produce
2589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         * the same result. But this block exists to give the JIT
2599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         * a better chance of optimizing a tight and common loop which
2609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         * occurs when writing out ASCII characters.
2619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         */
2629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        char c;
2639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        for(; i < n && (c = chars[i])< 0x80 ; i++ )
2649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            buf_loc[count_loc++] = (byte)c;
2659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
2669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    for (; i < n; i++)
2679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
2689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      final char c = chars[i];
2709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if (c < 0x80)
2729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        buf_loc[count_loc++] = (byte) (c);
2739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      else if (c < 0x800)
2749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
2759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        buf_loc[count_loc++] = (byte) (0xc0 + (c >> 6));
2769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        buf_loc[count_loc++] = (byte) (0x80 + (c & 0x3f));
2779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
2789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      /**
2799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        * The following else if condition is added to support XML 1.1 Characters for
2809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        * UTF-8:   [1111 0uuu] [10uu zzzz] [10yy yyyy] [10xx xxxx]*
2819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        * Unicode: [1101 10ww] [wwzz zzyy] (high surrogate)
2829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        *          [1101 11yy] [yyxx xxxx] (low surrogate)
2839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        *          * uuuuu = wwww + 1
2849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        */
2859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      else if (c >= 0xD800 && c <= 0xDBFF)
2869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
2879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          char high, low;
2889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          high = c;
2899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          i++;
2909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          low = chars[i];
2919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          buf_loc[count_loc++] = (byte) (0xF0 | (((high + 0x40) >> 8) & 0xf0));
2939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          buf_loc[count_loc++] = (byte) (0x80 | (((high + 0x40) >> 2) & 0x3f));
2949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          buf_loc[count_loc++] = (byte) (0x80 | ((low >> 6) & 0x0f) + ((high << 4) & 0x30));
2959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          buf_loc[count_loc++] = (byte) (0x80 | (low & 0x3f));
2969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
2979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      else
2989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
2999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        buf_loc[count_loc++] = (byte) (0xe0 + (c >> 12));
3009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        buf_loc[count_loc++] = (byte) (0x80 + ((c >> 6) & 0x3f));
3019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        buf_loc[count_loc++] = (byte) (0x80 + (c & 0x3f));
3029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
3039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
3049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // Store the local integer back into the instance variable
3059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    count = count_loc;
3069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
3089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
3109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Write a string.
3119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
3129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param  s  String to be written
3139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
3149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @exception  IOException  If an I/O error occurs
3159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
3169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void write(final String s) throws IOException
3179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
3189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // We multiply the length by three since this is the maximum length
3209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // of the characters that we can put into the buffer.  It is possible
3219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // for each Unicode character to expand to three bytes.
3229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    final int length = s.length();
3239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    int lengthx3 = 3*length;
3249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if (lengthx3 >= BYTES_MAX - count)
3269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
3279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // The requested length is greater than the unused part of the buffer
3289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      flushBuffer();
3299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if (lengthx3 > BYTES_MAX)
3319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
3329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        /*
3339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         * The requested length exceeds the size of the buffer,
3349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         * so break it up in chunks that don't exceed the buffer size.
3359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         */
3369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         final int start = 0;
3379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         int split = length/CHARS_MAX;
3389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         final int chunks;
3399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         if (length % CHARS_MAX > 0)
3409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson             chunks = split + 1;
3419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         else
3429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson             chunks = split;
3439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         int end_chunk = 0;
3449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         for (int chunk = 1; chunk <= chunks; chunk++)
3459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         {
3469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson             int start_chunk = end_chunk;
3479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson             end_chunk = start + (int) ((((long) length) * chunk) / chunks);
3489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson             s.getChars(start_chunk,end_chunk, m_inputChars,0);
3499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson             int len_chunk = (end_chunk - start_chunk);
3509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson             // Adjust the end of the chunk if it ends on a high char
3529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson             // of a Unicode surrogate pair and low char of the pair
3539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson             // is not going to be in the same chunk
3549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson             final char c = m_inputChars[len_chunk - 1];
3559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson             if (c >= 0xD800 && c <= 0xDBFF) {
3569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                 // Exclude char in this chunk,
3579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                 // to avoid spanning a Unicode character
3589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                 // that is in two Java chars as a high/low surrogate
3599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                 end_chunk--;
3609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                 len_chunk--;
3619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                 if (chunk == chunks) {
3629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                     /* TODO: error message needed.
3639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                      * The String incorrectly ends in a high char
3649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                      * of a high/low surrogate pair, but there is
3659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                      * no corresponding low as the high is the last char
3669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                      * Recover by ignoring this last char.
3679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                      */
3689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                 }
3699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson             }
3709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson             this.write(m_inputChars,0, len_chunk);
3729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         }
3739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         return;
3749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
3759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
3769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    s.getChars(0, length , m_inputChars, 0);
3799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    final char[] chars = m_inputChars;
3809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    final int n = length;
3819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    final byte[] buf_loc = m_outputBytes; // local reference for faster access
3829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    int count_loc = count;      // local integer for faster access
3839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    int i = 0;
3849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
3859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        /* This block could be omitted and the code would produce
3869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         * the same result. But this block exists to give the JIT
3879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         * a better chance of optimizing a tight and common loop which
3889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         * occurs when writing out ASCII characters.
3899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         */
3909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        char c;
3919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        for(; i < n && (c = chars[i])< 0x80 ; i++ )
3929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            buf_loc[count_loc++] = (byte)c;
3939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
3949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    for (; i < n; i++)
3959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
3969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      final char c = chars[i];
3989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
3999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if (c < 0x80)
4009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        buf_loc[count_loc++] = (byte) (c);
4019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      else if (c < 0x800)
4029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
4039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        buf_loc[count_loc++] = (byte) (0xc0 + (c >> 6));
4049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        buf_loc[count_loc++] = (byte) (0x80 + (c & 0x3f));
4059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
4069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    /**
4079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      * The following else if condition is added to support XML 1.1 Characters for
4089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      * UTF-8:   [1111 0uuu] [10uu zzzz] [10yy yyyy] [10xx xxxx]*
4099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      * Unicode: [1101 10ww] [wwzz zzyy] (high surrogate)
4109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      *          [1101 11yy] [yyxx xxxx] (low surrogate)
4119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      *          * uuuuu = wwww + 1
4129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      */
4139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    else if (c >= 0xD800 && c <= 0xDBFF)
4149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
4159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        char high, low;
4169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        high = c;
4179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        i++;
4189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        low = chars[i];
4199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        buf_loc[count_loc++] = (byte) (0xF0 | (((high + 0x40) >> 8) & 0xf0));
4219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        buf_loc[count_loc++] = (byte) (0x80 | (((high + 0x40) >> 2) & 0x3f));
4229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        buf_loc[count_loc++] = (byte) (0x80 | ((low >> 6) & 0x0f) + ((high << 4) & 0x30));
4239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        buf_loc[count_loc++] = (byte) (0x80 | (low & 0x3f));
4249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
4259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      else
4269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
4279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        buf_loc[count_loc++] = (byte) (0xe0 + (c >> 12));
4289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        buf_loc[count_loc++] = (byte) (0x80 + ((c >> 6) & 0x3f));
4299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        buf_loc[count_loc++] = (byte) (0x80 + (c & 0x3f));
4309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
4319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
4329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // Store the local integer back into the instance variable
4339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    count = count_loc;
4349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
4369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
4389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Flush the internal buffer
4399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
4409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @throws IOException
4419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
4429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void flushBuffer() throws IOException
4439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
4449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if (count > 0)
4469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
4479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      m_os.write(m_outputBytes, 0, count);
4489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      count = 0;
4509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
4519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
4529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
4549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Flush the stream.  If the stream has saved any characters from the
4559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * various write() methods in a buffer, write them immediately to their
4569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * intended destination.  Then, if that destination is another character or
4579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * byte stream, flush it.  Thus one flush() invocation will flush all the
4589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * buffers in a chain of Writers and OutputStreams.
4599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
4609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @exception  IOException  If an I/O error occurs
4619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
4629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @throws java.io.IOException
4639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
4649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void flush() throws java.io.IOException
4659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
4669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    flushBuffer();
4679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_os.flush();
4689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
4699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
4719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Close the stream, flushing it first.  Once a stream has been closed,
4729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * further write() or flush() invocations will cause an IOException to be
4739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * thrown.  Closing a previously-closed stream, however, has no effect.
4749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
4759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @exception  IOException  If an I/O error occurs
4769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
4779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @throws java.io.IOException
4789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
4799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public void close() throws java.io.IOException
4809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
4819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    flushBuffer();
4829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_os.close();
4839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
4849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
4869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Get the output stream where the events will be serialized to.
4879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
4889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return reference to the result stream, or null of only a writer was
4899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * set.
4909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
4919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public OutputStream getOutputStream()
4929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
4939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    return m_os;
4949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
4959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
4969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public Writer getWriter()
4979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
4989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // Only one of getWriter() or getOutputStream() can return null
4999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // This type of writer wraps an OutputStream, not a Writer.
5009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    return null;
5019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
5029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
503