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