/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  }