/Users/lyon/j4p/src/rtf/RtfUtil.java
|
1 /**
2 Christopher Scaglione
3 SW409
4 Midterm
5 */
6
7 package rtf;
8
9 import futils.ReaderUtil;
10 import futils.WriterUtil;
11
12 import java.io.BufferedReader;
13 import java.io.BufferedWriter;
14 import java.io.File;
15 import java.io.IOException;
16 import java.util.StringTokenizer;
17
18 public class RtfUtil implements JavaText, initAndProcess {
19
20 public static final String HEADER =
21 "{\\rtf1\\ansi\\ansicpg1252\\deff0" +
22 "\\deflang1033" +
23 "{\\fonttbl{\\f0\\fswiss" +
24 "\\fcharset0 Arial;}}" +
25 "\\viewkind4\\uc1\\pard\\f0\\fs20";
26
27 private boolean javaDocComment = false;
28 private boolean cStyleComment = false;
29 private boolean cppStyleComment = false;
30 private int quoteCount = 0;
31 private BufferedWriter bw = null;
32
33 /**
34 Converts a Java source file to a RTF file.
35 @author Christopher Scaglione
36 @param br is the BufferedReader to read from.
37 @param _bw is the BufferedWriter to write to.
38 */
39 public void javaToRtf(BufferedReader br, BufferedWriter _bw) {
40 String line = null;
41
42 try {
43 initAndProcess(_bw, br);
44
45 } catch (IOException e) {
46 e.printStackTrace();
47 }
48 }
49
50 private void initAndProcess(BufferedWriter _bw, BufferedReader br)
51 throws IOException {
52 String line;
53 bw = _bw;
54
55 write(HEADER);
56
57 while ((line = ReaderUtil.readLine(br)) != null)
58 processLine(line);
59
60 write("}");
61 bw.flush();
62
63 ReaderUtil.close(br);
64 }
65
66 /**
67 Converts a Java source file to a RTF file.
68 @author Christopher Scaglione
69 @param javaFile is the Java source file to convert.
70 @param rtfFile is the RTF file to convert to.
71 */
72 public void javaToRtf(File javaFile, File rtfFile) {
73 javaToRtf(ReaderUtil.getBufferedReader(javaFile),
74 WriterUtil.getBufferedWriter(rtfFile));
75 }
76
77 /**
78 Converts a line of Java source to RTF format.
79 @author Christopher Scaglione
80 @param line is the line of Java source to convert.
81 */
82 private void processLine(String line) {
83 String token = null;
84
85 // The delimiters have special codes in RTF, so we want
86 // them to be returned by the StringTokenizer.
87 StringTokenizer st = new StringTokenizer(line, " \t\n\r\f", true);
88
89 processTokenizer(st);
90
91 }
92
93 private void processTokenizer(StringTokenizer st) {
94 String token;
95 while (st.hasMoreTokens()) {
96 processToken(st);
97 }
98
99 write(getPar());
100
101 // C++-style comments can only span a single line,
102 // so reset the flag after the line is parsed.
103 cppStyleComment = false;
104 }
105
106 private void processToken(StringTokenizer st) {
107 String token;
108 token = st.nextToken();
109 if (isTokenSpace(token)) {
110 write(" ");
111 return;
112 }
113 if (isTokenTab(token)) {
114 write(getTab());
115 return;
116 }
117 if (isTokenNewLineReturnOrFormFeed(token)) {
118 write(getPar());
119 return;
120 }
121 processNoneReturnString(token);
122 }
123
124 private boolean isTokenSpace(String token) {
125 return token.equals(" ");
126 }
127
128 private boolean isTokenTab(String token) {
129 return token.equals("\t");
130 }
131
132 private boolean isTokenNewLineReturnOrFormFeed(String token) {
133 return token.equals("\n") ||
134 token.equals("\r") ||
135 token.equals("\f");
136 }
137
138 /**
139 Converts a token of Java source to RTF format.
140 @author Christopher Scaglione
141 @param _token is the token of Java source to convert.
142 */
143 private void processNoneReturnString(String _token) {
144 boolean reservedWord = false;
145 String token = null;
146 String previousToken = null;
147 String previousPreviousToken = null;
148
149 // The token needs to be parsed again to determine if it is a reserved
150 // word since reserved words may be right next to other characters.
151 // For example, "for(i = 0", "boolean b = true;".
152 StringTokenizer st = new StringTokenizer(_token,
153 "\";><=&|!(){}[],\\.:", true);
154
155 processCoreTokenizer(st, previousPreviousToken, previousToken);
156
157 }
158
159 private void processCoreTokenizer(
160 StringTokenizer st,
161 String previousPreviousToken,
162 String previousToken) {
163 boolean reservedWord;
164 String token;
165 while (st.hasMoreTokens()) {
166 reservedWord = false;
167
168 token = st.nextToken();
169
170 checkForStartComment(token);
171
172 // JavaDoc comments will be italic.
173 if (javaDocComment == true) {
174 write(getItalic(token));
175
176 // Check if we have reached the end of the
177 // JavaDoc comment. If we have, reset the
178 // flag.
179 if (checkForEndComment(token) == true) {
180 javaDocComment = false;
181 }
182 } else {
183 // C-style comments will be plain.
184 if (cStyleComment == true) {
185 write(getPlain(token));
186
187 // Check if we have reached the end of the
188 // C-style comment. If we have, reset the
189 // flag.
190 if (checkForEndComment(token) == true) {
191 cStyleComment = false;
192 }
193 } else {
194 // C++-style comments will be plain.
195 if (cppStyleComment == true) {
196 write(getPlain(token));
197 } else {
198 if (checkForStringQuote(previousPreviousToken, previousToken, token) == true) {
199 quoteCount++;
200 }
201
202 // If quoteCount is 1, then we are within a string
203 // and reserved words do not need to be made bold.
204 if (quoteCount != 1) {
205 // Check if this token is a reserved word.
206 reservedWord = CheckIfTokenIsReservedWord(
207 token, reservedWord);
208 }
209
210 if (reservedWord == false)
211 write(getPlain(token));
212
213
214 // If quoteCount is 2, we have found the
215 // start and end parentheses for a string,
216 // so reset quoteCount.
217 if (quoteCount == 2)
218 quoteCount = 0;
219
220 }
221 }
222 }
223
224 // Keep track of the 2 previous tokens.
225 // This is needed to determine a string quote.
226 previousPreviousToken = previousToken;
227 previousToken = token;
228 }
229 }
230
231 private boolean CheckIfTokenIsReservedWord(String token, boolean reservedWord) {
232 if (isJavaReservedWord(token) == true) {
233 reservedWord = true;
234 write(getBold(token));
235 }
236 return reservedWord;
237 }
238
239 /**
240 Determines if the token contains the start of comment
241 designator for a JavaDoc comment, C-style comment, or
242 C++-style comment and sets the appropriate flag.
243 @author Christopher Scaglione
244 @param The token to search.
245 */
246 private void checkForStartComment(String token) {
247 // If the quote count is 1, then we are currently
248 // inside a string and we do not care if we find
249 // the start of comment designator since it is part
250 // of the string.
251 if (quoteCount != 1) {
252 if (token.indexOf("/**") != -1) {
253 javaDocComment = true;
254 } else {
255 if (token.indexOf("/*") != -1) {
256 cStyleComment = true;
257 } else {
258 if (token.indexOf("//") != -1) {
259 cppStyleComment = true;
260 }
261 }
262 }
263 }
264 }
265
266 /**
267 Determines if the token contains the end of comment
268 designator.
269 @author Christopher Scaglione
270 @param The token to search.
271 @return True if the end of comment designator was found,
272 false otherwise.
273 */
274 private boolean checkForEndComment(String token) {
275 boolean endComment = false;
276
277 // If the quote count is 1, then we are currently
278 // inside a string and we do not care if we find
279 // the end of comment designator since it is part
280 // of the string.
281 if (quoteCount != 1) {
282 if (token.indexOf("*/") != -1) {
283 endComment = true;
284 }
285 }
286
287 return endComment;
288 }
289
290 /**
291 Determines if the token contains a string quote. To make
292 this determination requires the 2 previous tokens.
293 @author Christopher Scaglione
294 @param previousPreviousToken is the token immediately
295 before previousToken.
296 @param previousToken is the token immediately before token.
297 @param token is the token to search.
298 */
299 private boolean checkForStringQuote(String previousPreviousToken, String previousToken, String token) {
300 boolean stringQuote = false;
301
302 // If one of the comment flags is true, then
303 // the quote is part of the comment.
304 if (javaDocComment == false &&
305 cStyleComment == false &&
306 cppStyleComment == false) {
307
308 if (token.indexOf("\"") != -1) {
309 stringQuote = true;
310
311 if (previousToken != null) {
312 // Check if the quote is preceded by a backslash.
313 // If it is, then this could be a quote within
314 // a string (\").
315 if (previousToken.equals("\\") == true) {
316 stringQuote = false;
317
318 if (previousPreviousToken != null) {
319 // Check if the backslash is preceded by another
320 // backslash. If it is, then this is a quote since
321 // the 2 previous tokens make up a backslash in
322 // a string.
323 if (previousPreviousToken.equals("\\") == true) {
324 stringQuote = true;
325 }
326 }
327 }
328 }
329 }
330 }
331
332 return stringQuote;
333 }
334
335 /**
336 Checks if the given token is a Java reserved word.
337 @author Christopher Scaglione
338 @param The token to check.
339 @return True if the token is a reserved word,
340 false otherwise.
341 */
342 private boolean isJavaReservedWord(String token) {
343 boolean reservedWord = false;
344
345 for (int i = 0; i < javaReservedWords.length; i++) {
346 if (token.compareTo(javaReservedWords[i]) == 0) {
347 reservedWord = true;
348 break;
349 }
350 }
351
352 return reservedWord;
353 }
354
355 /**
356 Writes a string to the BufferedWriter.
357 @author Christopher Scaglione
358 @param s is the string to write to the BufferedWriter.
359 */
360 private void write(String s) {
361 try {
362 bw.write(s, 0, s.length());
363 } catch (IOException e) {
364 e.printStackTrace();
365 }
366 }
367
368 /**
369 Returns a string in italic RTF format.
370 @author Christopher Scaglione
371 @param s is the string to format.
372 @return A string in italic RTF format.
373 */
374 public static String getItalic(String s) {
375 return "{\\i " + formatCurlyBracesAndBackslashes(s) + "}";
376 }
377
378 /**
379 Returns a string in bold RTF format.
380 @author Christopher Scaglione
381 @param s is the string to format.
382 @return A string in bold RTF format.
383 */
384 public static String getBold(String s) {
385 return "{\\b " + formatCurlyBracesAndBackslashes(s) + "}";
386 }
387
388 /**
389 Returns a string in plain RTF format.
390 @author Christopher Scaglione
391 @param s is the string to format.
392 @return A string in plain RTF format.
393 */
394 public static String getPlain(String s) {
395 return "{" + formatCurlyBracesAndBackslashes(s) + "}";
396 }
397
398 /**
399 Returns a paragraph break in RTF format.
400 @author Christopher Scaglione
401 @return A paragraph break in RTF format.
402 */
403 public static String getPar() {
404 return "{\\par}";
405 }
406
407 /**
408 Returns a tab in RTF format.
409 @author Christopher Scaglione
410 @return A tab in RTF format.
411 */
412 public static String getTab() {
413 return "{\\tab}";
414 }
415
416 /**
417 Returns a string with curly braces and backslashes in RTF format.
418 Any displayed curly braces or backslashes in RTF must be preceded by
419 a "\" since "{", "}", and "\" are used for control characters.
420 @author Christopher Scaglione
421 @param s is the string to format.
422 @return A string with curly braces in RTF format.
423 */
424 public static String formatCurlyBracesAndBackslashes(String s) {
425 String formattedString = "";
426 char ch;
427
428 for (int i = 0; i < s.length(); i++) {
429 ch = s.charAt(i);
430 if (ch == '{' || ch == '}' || ch == '\\') {
431 formattedString = formattedString.concat("\\");
432 }
433
434 formattedString = formattedString.concat(String.valueOf(ch));
435 }
436
437 return formattedString;
438 }
439 }