1 /* RTFScanner.java -- 2 Copyright (C) 2005 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package javax.swing.text.rtf; 40 41 import java.io.BufferedReader; 42 import java.io.IOException; 43 import java.io.InputStream; 44 import java.io.InputStreamReader; 45 import java.io.Reader; 46 47 /** 48 * Provides a scanner that scans an {@link InputStream} for tokens of the 49 * RTF syntax. 50 * 51 * This scanner is based upon the RTF specification 1.6 52 * available at: 53 * 54 * <a 55 * href="http://msdn.microsoft.com/library/en-us/dnrtfspec/html/rtfspec.asp"> 56 * RTF specification at MSDN</a> 57 * 58 * @author Roman Kennke (roman@ontographics.com) 59 */ 60 class RTFScanner 61 { 62 63 /** 64 * The reader from which we read the RTF data. 65 */ 66 private Reader in; 67 68 /** 69 * This is used to constuct strings from the read in chars. 70 */ 71 private StringBuffer buffer; 72 73 /** 74 * Constructs a new RTFScanner without initializing the {@link Reader}. 75 */ RTFScanner()76 private RTFScanner() 77 { 78 buffer = new StringBuffer(); 79 } 80 81 /** 82 * Constructs a new RTFScanner for the given {@link InputStream}. 83 * The stream is wrapped into an {@link InputStreamReader} and if it's 84 * not yet buffered then the Reader is wrapped in a {@link BufferedReader} 85 * 86 * @param stream the {@link InputStream} to read RTF data from 87 */ RTFScanner(InputStream stream)88 public RTFScanner(InputStream stream) 89 { 90 this(); 91 InputStreamReader reader = new InputStreamReader(stream); 92 in = new BufferedReader(reader); 93 } 94 95 /** 96 * Constructs a new RTFScanner for the given {@link Reader}. 97 * 98 * If the reader is not an instance of {@link BufferedReader} then it 99 * is wrapped into a BufferedReader. 100 * 101 * @param reader the {@link BufferedReader} to read RTF data from 102 */ RTFScanner(Reader reader)103 public RTFScanner(Reader reader) 104 { 105 this(); 106 if (reader instanceof BufferedReader) 107 { 108 in = reader; 109 } 110 else 111 { 112 in = new BufferedReader(reader); 113 } 114 } 115 116 /** 117 * Reads in the next {@link Token} from the stream. 118 * 119 * @return the read {@link Token} 120 * 121 * @throws IOException if the underlying stream has problems 122 */ readToken()123 public Token readToken() 124 throws IOException 125 { 126 Token token = null; 127 128 int c = in.read(); 129 switch(c) 130 { 131 case -1: 132 token = new Token(Token.EOF); 133 break; 134 135 case '{': 136 token = new Token(Token.LCURLY); 137 break; 138 139 case '}': 140 token = new Token(Token.RCURLY); 141 break; 142 143 case '\\': 144 buffer.delete(0, buffer.length()); 145 buffer.append((char) c); 146 token = readControlWord(); 147 break; 148 149 default: 150 buffer.delete(0, buffer.length()); 151 buffer.append((char) c); 152 token = readText(); 153 break; 154 } 155 156 return token; 157 } 158 159 /** 160 * Reads in a control word and optional parameter. 161 * 162 * @return the read in control word as {@link ControlWordToken} 163 * 164 * @throws IOException if the underlying stream has problems 165 */ readControlWord()166 private Token readControlWord() 167 throws IOException 168 { 169 // this flag indicates if we are still reading the name or are already 170 // in the parameter 171 boolean readingName = true; 172 String name = null; 173 String param = null; 174 175 while (true) 176 { 177 in.mark(1); 178 int c = in.read(); 179 180 // check for 'a'..'z' 181 if (readingName && (c >= 'a') && (c <= 'z')) 182 { 183 buffer.append((char) c); 184 } 185 else if ((c >= '0') && (c <= '9')) 186 { 187 // if the last char was in the name, then finish reading the name 188 if (readingName) 189 { 190 name = buffer.toString(); 191 buffer.delete(0, buffer.length()); 192 readingName = false; 193 } 194 buffer.append((char) c); 195 } 196 else 197 { 198 // if we were in the name, then finish this 199 if (readingName) 200 { 201 name = buffer.toString(); 202 } 203 // otherwise finish the parameter 204 else 205 { 206 param = buffer.toString(); 207 } 208 209 // clear up 210 buffer.delete(0, buffer.length()); 211 // reset input buffer to last char 212 in.reset(); 213 // break while loop 214 break; 215 } 216 } 217 218 ControlWordToken token = null; 219 220 if (param == null) 221 token = new ControlWordToken(name); 222 else 223 token =new ControlWordToken(name, Integer.parseInt(param)); 224 225 return token; 226 227 } 228 229 /** 230 * Reads in a block of text. 231 * 232 * @return the token for the text 233 */ readText()234 private Token readText() 235 throws IOException 236 { 237 238 boolean readingText = true; 239 while (readingText) 240 { 241 in.mark(1); 242 int c = in.read(); 243 switch(c) 244 { 245 case '\\': 246 case '{': 247 case '}': 248 case -1: 249 readingText = false; 250 in.reset(); 251 break; 252 253 default: 254 buffer.append((char) c); 255 break; 256 } 257 258 } 259 260 String text = buffer.toString(); 261 Token token = new TextToken(text); 262 263 buffer.delete(0, buffer.length()); 264 265 return token; 266 267 } 268 } 269