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