/plugins/office/ext/src/xalan-j_2_7_1/src/org/apache/xml/serializer/SerializerTraceWriter.java

https://github.com/srnsw/xena · Java · 341 lines · 152 code · 44 blank · 145 comment · 31 complexity · 3692dcf6e1755cb6bbd4c2aeef9b1050 MD5 · raw file

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