blob: d1233ecd1e94679472877bba03f7a701bb2f5536 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25package javax.swing.text.rtf;
26
27import java.io.*;
28import java.lang.*;
29
30/**
31 * A generic superclass for streams which read and parse text
32 * consisting of runs of characters interspersed with occasional
33 * ``specials'' (formatting characters).
34 *
35 * <p> Most of the functionality
36 * of this class would be redundant except that the
37 * <code>ByteToChar</code> converters
38 * are suddenly private API. Presumably this class will disappear
39 * when the API is made public again. (sigh) That will also let us handle
40 * multibyte character sets...
41 *
42 * <P> A subclass should override at least <code>write(char)</code>
43 * and <code>writeSpecial(int)</code>. For efficiency's sake it's a
44 * good idea to override <code>write(String)</code> as well. The subclass'
45 * initializer may also install appropriate translation and specials tables.
46 *
47 * @see OutputStream
48 */
49abstract class AbstractFilter extends OutputStream
50{
51 /** A table mapping bytes to characters */
52 protected char translationTable[];
53 /** A table indicating which byte values should be interpreted as
54 * characters and which should be treated as formatting codes */
55 protected boolean specialsTable[];
56
57 /** A translation table which does ISO Latin-1 (trivial) */
58 static final char latin1TranslationTable[];
59 /** A specials table which indicates that no characters are special */
60 static final boolean noSpecialsTable[];
61 /** A specials table which indicates that all characters are special */
62 static final boolean allSpecialsTable[];
63
64 static {
65 int i;
66
67 noSpecialsTable = new boolean[256];
68 for (i = 0; i < 256; i++)
69 noSpecialsTable[i] = false;
70
71 allSpecialsTable = new boolean[256];
72 for (i = 0; i < 256; i++)
73 allSpecialsTable[i] = true;
74
75 latin1TranslationTable = new char[256];
76 for (i = 0; i < 256; i++)
77 latin1TranslationTable[i] = (char)i;
78 }
79
80 /**
81 * A convenience method that reads text from a FileInputStream
82 * and writes it to the receiver.
83 * The format in which the file
84 * is read is determined by the concrete subclass of
85 * AbstractFilter to which this method is sent.
86 * <p>This method does not close the receiver after reaching EOF on
87 * the input stream.
88 * The user must call <code>close()</code> to ensure that all
89 * data are processed.
90 *
91 * @param in An InputStream providing text.
92 */
93 public void readFromStream(InputStream in)
94 throws IOException
95 {
96 byte buf[];
97 int count;
98
99 buf = new byte[16384];
100
101 while(true) {
102 count = in.read(buf);
103 if (count < 0)
104 break;
105
106 this.write(buf, 0, count);
107 }
108 }
109
110 public void readFromReader(Reader in)
111 throws IOException
112 {
113 char buf[];
114 int count;
115
116 buf = new char[2048];
117
118 while(true) {
119 count = in.read(buf);
120 if (count < 0)
121 break;
122 for (int i = 0; i < count; i++) {
123 this.write(buf[i]);
124 }
125 }
126 }
127
128 public AbstractFilter()
129 {
130 translationTable = latin1TranslationTable;
131 specialsTable = noSpecialsTable;
132 }
133
134 /**
135 * Implements the abstract method of OutputStream, of which this class
136 * is a subclass.
137 */
138 public void write(int b)
139 throws IOException
140 {
141 if (b < 0)
142 b += 256;
143 if (specialsTable[b])
144 writeSpecial(b);
145 else {
146 char ch = translationTable[b];
147 if (ch != (char)0)
148 write(ch);
149 }
150 }
151
152 /**
153 * Implements the buffer-at-a-time write method for greater
154 * efficiency.
155 *
156 * <p> <strong>PENDING:</strong> Does <code>write(byte[])</code>
157 * call <code>write(byte[], int, int)</code> or is it the other way
158 * around?
159 */
160 public void write(byte[] buf, int off, int len)
161 throws IOException
162 {
163 StringBuffer accumulator = null;
164 while (len > 0) {
165 short b = (short)buf[off];
166
167 // stupid signed bytes
168 if (b < 0)
169 b += 256;
170
171 if (specialsTable[b]) {
172 if (accumulator != null) {
173 write(accumulator.toString());
174 accumulator = null;
175 }
176 writeSpecial(b);
177 } else {
178 char ch = translationTable[b];
179 if (ch != (char)0) {
180 if (accumulator == null)
181 accumulator = new StringBuffer();
182 accumulator.append(ch);
183 }
184 }
185
186 len --;
187 off ++;
188 }
189
190 if (accumulator != null)
191 write(accumulator.toString());
192 }
193
194 /**
195 * Hopefully, all subclasses will override this method to accept strings
196 * of text, but if they don't, AbstractFilter's implementation
197 * will spoon-feed them via <code>write(char)</code>.
198 *
199 * @param s The string of non-special characters written to the
200 * OutputStream.
201 */
202 public void write(String s)
203 throws IOException
204 {
205 int index, length;
206
207 length = s.length();
208 for(index = 0; index < length; index ++) {
209 write(s.charAt(index));
210 }
211 }
212
213 /**
214 * Subclasses must provide an implementation of this method which
215 * accepts a single (non-special) character.
216 *
217 * @param ch The character written to the OutputStream.
218 */
219 protected abstract void write(char ch) throws IOException;
220
221 /**
222 * Subclasses must provide an implementation of this method which
223 * accepts a single special byte. No translation is performed
224 * on specials.
225 *
226 * @param b The byte written to the OutputStream.
227 */
228 protected abstract void writeSpecial(int b) throws IOException;
229}