1. /*
  2. * @(#)AbstractFilter.java 1.10 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.text.rtf;
  8. import java.io.*;
  9. import java.lang.*;
  10. /**
  11. * A generic superclass for streams which read and parse text
  12. * consisting of runs of characters interspersed with occasional
  13. * ``specials'' (formatting characters).
  14. *
  15. * <p> Most of the functionality
  16. * of this class would be redundant except that the
  17. * <code>ByteToChar</code> converters
  18. * are suddenly private API. Presumably this class will disappear
  19. * when the API is made public again. (sigh) That will also let us handle
  20. * multibyte character sets...
  21. *
  22. * <P> A subclass should override at least <code>write(char)</code>
  23. * and <code>writeSpecial(int)</code>. For efficiency's sake it's a
  24. * good idea to override <code>write(String)</code> as well. The subclass'
  25. * initializer may also install appropriate translation and specials tables.
  26. *
  27. * @see OutputStream
  28. */
  29. abstract class AbstractFilter extends OutputStream
  30. {
  31. /** A table mapping bytes to characters */
  32. protected char translationTable[];
  33. /** A table indicating which byte values should be interpreted as
  34. * characters and which should be treated as formatting codes */
  35. protected boolean specialsTable[];
  36. /** A translation table which does ISO Latin-1 (trivial) */
  37. static final char latin1TranslationTable[];
  38. /** A specials table which indicates that no characters are special */
  39. static final boolean noSpecialsTable[];
  40. /** A specials table which indicates that all characters are special */
  41. static final boolean allSpecialsTable[];
  42. static {
  43. int i;
  44. noSpecialsTable = new boolean[256];
  45. for (i = 0; i < 256; i++)
  46. noSpecialsTable[i] = false;
  47. allSpecialsTable = new boolean[256];
  48. for (i = 0; i < 256; i++)
  49. allSpecialsTable[i] = true;
  50. latin1TranslationTable = new char[256];
  51. for (i = 0; i < 256; i++)
  52. latin1TranslationTable[i] = (char)i;
  53. }
  54. /**
  55. * A convenience method that reads text from a FileInputStream
  56. * and writes it to the receiver.
  57. * The format in which the file
  58. * is read is determined by the concrete subclass of
  59. * AbstractFilter to which this method is sent.
  60. * <p>This method does not close the receiver after reaching EOF on
  61. * the input stream.
  62. * The user must call <code>close()</code> to ensure that all
  63. * data are processed.
  64. *
  65. * @param in An InputStream providing text.
  66. */
  67. public void readFromStream(InputStream in)
  68. throws IOException
  69. {
  70. byte buf[];
  71. int count;
  72. buf = new byte[16384];
  73. while(true) {
  74. count = in.read(buf);
  75. if (count < 0)
  76. break;
  77. this.write(buf, 0, count);
  78. }
  79. }
  80. public void readFromReader(Reader in)
  81. throws IOException
  82. {
  83. char buf[];
  84. int count;
  85. buf = new char[2048];
  86. while(true) {
  87. count = in.read(buf);
  88. if (count < 0)
  89. break;
  90. for (int i = 0; i < count; i++) {
  91. this.write(buf[i]);
  92. }
  93. }
  94. }
  95. public AbstractFilter()
  96. {
  97. translationTable = latin1TranslationTable;
  98. specialsTable = noSpecialsTable;
  99. }
  100. /**
  101. * Implements the abstract method of OutputStream, of which this class
  102. * is a subclass.
  103. */
  104. public void write(int b)
  105. throws IOException
  106. {
  107. if (b < 0)
  108. b += 256;
  109. if (specialsTable[b])
  110. writeSpecial(b);
  111. else {
  112. char ch = translationTable[b];
  113. if (ch != (char)0)
  114. write(ch);
  115. }
  116. }
  117. /**
  118. * Implements the buffer-at-a-time write method for greater
  119. * efficiency.
  120. *
  121. * <p> <strong>PENDING:</strong> Does <code>write(byte[])</code>
  122. * call <code>write(byte[], int, int)</code> or is it the other way
  123. * around?
  124. */
  125. public void write(byte[] buf, int off, int len)
  126. throws IOException
  127. {
  128. StringBuffer accumulator = null;
  129. while (len > 0) {
  130. short b = (short)buf[off];
  131. // stupid signed bytes
  132. if (b < 0)
  133. b += 256;
  134. if (specialsTable[b]) {
  135. if (accumulator != null) {
  136. write(accumulator.toString());
  137. accumulator = null;
  138. }
  139. writeSpecial(b);
  140. } else {
  141. char ch = translationTable[b];
  142. if (ch != (char)0) {
  143. if (accumulator == null)
  144. accumulator = new StringBuffer();
  145. accumulator.append(ch);
  146. }
  147. }
  148. len --;
  149. off ++;
  150. }
  151. if (accumulator != null)
  152. write(accumulator.toString());
  153. }
  154. /**
  155. * Hopefully, all subclasses will override this method to accept strings
  156. * of text, but if they don't, AbstractFilter's implementation
  157. * will spoon-feed them via <code>write(char)</code>.
  158. *
  159. * @param s The string of non-special characters written to the
  160. * OutputStream.
  161. */
  162. public void write(String s)
  163. throws IOException
  164. {
  165. int index, length;
  166. length = s.length();
  167. for(index = 0; index < length; index ++) {
  168. write(s.charAt(index));
  169. }
  170. }
  171. /**
  172. * Subclasses must provide an implementation of this method which
  173. * accepts a single (non-special) character.
  174. *
  175. * @param ch The character written to the OutputStream.
  176. */
  177. protected abstract void write(char ch) throws IOException;
  178. /**
  179. * Subclasses must provide an implementation of this method which
  180. * accepts a single special byte. No translation is performed
  181. * on specials.
  182. *
  183. * @param b The byte written to the OutputStream.
  184. */
  185. protected abstract void writeSpecial(int b) throws IOException;
  186. }