OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / libcore / luni / src / main / java / org / apache / xml / serializer / SerializerTraceWriter.java
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the  "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 /*
19  * $Id: SerializerTraceWriter.java 468654 2006-10-28 07:09:23Z minchau $
20  */
21 package org.apache.xml.serializer;
22
23 import java.io.IOException;
24 import java.io.OutputStream;
25 import java.io.Writer;
26
27 /**
28  * This class wraps the real writer, it only purpose is to send
29  * CHARACTERTOSTREAM events to the trace listener. 
30  * Each method immediately sends the call to the wrapped writer unchanged, but
31  * in addition it collects characters to be issued to a trace listener.
32  * 
33  * In this way the trace
34  * listener knows what characters have been written to the output Writer.
35  * 
36  * There may still be differences in what the trace events say is going to the
37  * output writer and what is really going there. These differences will be due
38  * to the fact that this class is UTF-8 encoding before emiting the trace event
39  * and the underlying writer may not be UTF-8 encoding. There may also be
40  * encoding differences.  So the main pupose of this class is to provide a
41  * resonable facsimile of the true output.
42  * 
43  * @xsl.usage internal
44  */
45 final class SerializerTraceWriter extends Writer implements WriterChain
46 {
47
48     /** The real writer to immediately write to.
49      * This reference may be null, in which case nothing is written out, but
50      * only the trace events are fired for output.
51      */
52     private final java.io.Writer m_writer;
53
54     /** The tracer to send events to */
55     private final SerializerTrace m_tracer;
56
57     /** The size of the internal buffer, just to keep too many
58      * events from being sent to the tracer
59      */
60     private int buf_length;
61
62     /**
63      * Internal buffer to collect the characters to go to the trace listener.
64      * 
65      */
66     private byte buf[];
67
68     /**
69      * How many bytes have been collected and still need to go to trace
70      * listener.
71      */
72     private int count;
73
74     /**
75      * Creates or replaces the internal buffer, and makes sure it has a few
76      * extra bytes slight overflow of the last UTF8 encoded character.
77      * @param size
78      */
79     private void setBufferSize(int size)
80     {
81         buf = new byte[size + 3];
82         buf_length = size;
83         count = 0;
84     }
85
86     /**
87      * Constructor.
88      * If the writer passed in is null, then this SerializerTraceWriter will
89      * only signal trace events of what would have been written to that writer.
90      * If the writer passed in is not null then the trace events will mirror
91      * what is going to that writer. In this way tools, such as a debugger, can
92      * gather information on what is being written out.
93      * 
94      * @param out the Writer to write to (possibly null)
95      * @param tracer the tracer to inform that characters are being written
96      */
97     public SerializerTraceWriter(Writer out, SerializerTrace tracer)
98     {
99         m_writer = out;
100         m_tracer = tracer;
101         setBufferSize(1024);
102     }
103
104     /**
105      * Flush out the collected characters by sending them to the trace
106      * listener.  These characters are never written to the real writer
107      * (m_writer) because that has already happened with every method
108      * call. This method simple informs the listener of what has already
109      * happened.
110      * @throws IOException
111      */
112     private void flushBuffer() throws IOException
113     {
114
115         // Just for tracing purposes
116         if (count > 0)
117         {
118             char[] chars = new char[count];
119             for(int i=0; i<count; i++)
120                 chars[i] = (char) buf[i];
121
122             if (m_tracer != null)
123                 m_tracer.fireGenerateEvent(
124                     SerializerTrace.EVENTTYPE_OUTPUT_CHARACTERS,
125                     chars,
126                     0,
127                     chars.length);
128
129             count = 0;
130         }
131     }
132
133     /**
134      * Flush the internal buffer and flush the Writer
135      * @see java.io.Writer#flush()
136      */
137     public void flush() throws java.io.IOException
138     {
139         // send to the real writer
140         if (m_writer != null)
141             m_writer.flush();
142
143         // from here on just for tracing purposes
144         flushBuffer();
145     }
146
147     /**
148      * Flush the internal buffer and close the Writer
149      * @see java.io.Writer#close()
150      */
151     public void close() throws java.io.IOException
152     {
153         // send to the real writer
154         if (m_writer != null)   
155             m_writer.close();
156
157         // from here on just for tracing purposes
158         flushBuffer();
159     }
160
161
162     /**
163      * Write a single character.  The character to be written is contained in
164      * the 16 low-order bits of the given integer value; the 16 high-order bits
165      * are ignored.
166      *
167      * <p> Subclasses that intend to support efficient single-character output
168      * should override this method.
169      *
170      * @param c  int specifying a character to be written.
171      * @exception  IOException  If an I/O error occurs
172      */
173     public void write(final int c) throws IOException
174     {
175         // send to the real writer
176         if (m_writer != null)
177             m_writer.write(c);
178
179         // ---------- from here on just collect for tracing purposes
180
181         /* If we are close to the end of the buffer then flush it.
182          * Remember the buffer can hold a few more characters than buf_length
183          */
184         if (count >= buf_length)
185             flushBuffer();
186
187         if (c < 0x80)
188         {
189             buf[count++] = (byte) (c);
190         }
191         else if (c < 0x800)
192         {
193             buf[count++] = (byte) (0xc0 + (c >> 6));
194             buf[count++] = (byte) (0x80 + (c & 0x3f));
195         }
196         else
197         {
198             buf[count++] = (byte) (0xe0 + (c >> 12));
199             buf[count++] = (byte) (0x80 + ((c >> 6) & 0x3f));
200             buf[count++] = (byte) (0x80 + (c & 0x3f));
201         }
202     }
203
204     /**
205      * Write a portion of an array of characters.
206      *
207      * @param  chars  Array of characters
208      * @param  start   Offset from which to start writing characters
209      * @param  length   Number of characters to write
210      *
211      * @exception  IOException  If an I/O error occurs
212      *
213      * @throws java.io.IOException
214      */
215     public void write(final char chars[], final int start, final int length)
216         throws java.io.IOException
217     {
218         // send to the real writer
219         if (m_writer != null)
220             m_writer.write(chars, start, length);
221
222         // from here on just collect for tracing purposes
223         int lengthx3 = (length << 1) + length;
224
225         if (lengthx3 >= buf_length)
226         {
227
228             /* If the request length exceeds the size of the output buffer,
229               * flush the output buffer and make the buffer bigger to handle.
230               */
231
232             flushBuffer();
233             setBufferSize(2 * lengthx3);
234
235         }
236
237         if (lengthx3 > buf_length - count)
238         {
239             flushBuffer();
240         }
241
242         final int n = length + start;
243         for (int i = start; i < n; i++)
244         {
245             final char c = chars[i];
246
247             if (c < 0x80)
248                 buf[count++] = (byte) (c);
249             else if (c < 0x800)
250             {
251                 buf[count++] = (byte) (0xc0 + (c >> 6));
252                 buf[count++] = (byte) (0x80 + (c & 0x3f));
253             }
254             else
255             {
256                 buf[count++] = (byte) (0xe0 + (c >> 12));
257                 buf[count++] = (byte) (0x80 + ((c >> 6) & 0x3f));
258                 buf[count++] = (byte) (0x80 + (c & 0x3f));
259             }
260         }
261
262     }
263
264     /**
265      * Write a string.
266      *
267      * @param  s  String to be written
268      *
269      * @exception  IOException  If an I/O error occurs
270      */
271     public void write(final String s) throws IOException
272     {
273         // send to the real writer
274         if (m_writer != null)
275             m_writer.write(s);
276
277         // from here on just collect for tracing purposes
278         final int length = s.length();
279
280         // We multiply the length by three since this is the maximum length
281         // of the characters that we can put into the buffer.  It is possible
282         // for each Unicode character to expand to three bytes.
283
284         int lengthx3 = (length << 1) + length;
285
286         if (lengthx3 >= buf_length)
287         {
288
289             /* If the request length exceeds the size of the output buffer,
290               * flush the output buffer and make the buffer bigger to handle.
291               */
292
293             flushBuffer();
294             setBufferSize(2 * lengthx3);
295         }
296
297         if (lengthx3 > buf_length - count)
298         {
299             flushBuffer();
300         }
301
302         for (int i = 0; i < length; i++)
303         {
304             final char c = s.charAt(i);
305
306             if (c < 0x80)
307                 buf[count++] = (byte) (c);
308             else if (c < 0x800)
309             {
310                 buf[count++] = (byte) (0xc0 + (c >> 6));
311                 buf[count++] = (byte) (0x80 + (c & 0x3f));
312             }
313             else
314             {
315                 buf[count++] = (byte) (0xe0 + (c >> 12));
316                 buf[count++] = (byte) (0x80 + ((c >> 6) & 0x3f));
317                 buf[count++] = (byte) (0x80 + (c & 0x3f));
318             }
319         }
320     }
321
322     /**
323      * Get the writer that this one directly wraps.
324      */
325     public Writer getWriter()
326     {
327         return m_writer;
328     }
329
330     /**
331      * Get the OutputStream that is the at the end of the
332      * chain of writers.
333      */
334     public OutputStream getOutputStream()
335     {
336         OutputStream retval = null;
337         if (m_writer instanceof WriterChain)
338             retval = ((WriterChain) m_writer).getOutputStream();
339         return retval;
340     }
341 }