1 /* 2 * Copyright (c) 1997, 2018, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package javax.swing.text.rtf; 26 27 import java.io.*; 28 import 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 */ 49 abstract 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 StringBuilder 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 StringBuilder(); 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 }