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