View Javadoc
1   /**
2    * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3    */
4   package net.sourceforge.pmd.cpd;
5   
6   import java.io.File;
7   import java.io.FileInputStream;
8   import java.io.InputStreamReader;
9   import java.io.LineNumberReader;
10  import java.io.Reader;
11  import java.io.StringReader;
12  import java.lang.ref.SoftReference;
13  import java.util.ArrayList;
14  import java.util.List;
15  
16  import net.sourceforge.pmd.PMD;
17  
18  import org.apache.commons.io.ByteOrderMark;
19  import org.apache.commons.io.IOUtils;
20  import org.apache.commons.io.input.BOMInputStream;
21  
22  public class SourceCode {
23  
24      public static abstract class CodeLoader {
25          private SoftReference<List<String>> code;
26  
27          public List<String> getCode() {
28              List<String> c = null;
29              if (code != null) {
30                  c = code.get();
31              }
32              if (c != null) {
33                  return c;
34              }
35              this.code = new SoftReference<List<String>>(load());
36              return code.get();
37          }
38  
39          public abstract String getFileName();
40  
41          protected abstract Reader getReader() throws Exception;
42  
43          protected List<String> load() {
44              LineNumberReader lnr = null;
45              try {
46                  lnr = new LineNumberReader(getReader());
47                  List<String> lines = new ArrayList<String>();
48                  String currentLine;
49                  while ((currentLine = lnr.readLine()) != null) {
50                      lines.add(currentLine);
51                  }
52                  return lines;
53              } catch (Exception e) {
54                  e.printStackTrace();
55                  throw new RuntimeException("Problem while reading " + getFileName() + ":" + e.getMessage());
56              } finally {
57                  IOUtils.closeQuietly(lnr);
58              }
59          }
60      }
61  
62      public static class FileCodeLoader extends CodeLoader {
63          private File file;
64          private String encoding;
65  
66          public FileCodeLoader(File file, String encoding) {
67              this.file = file;
68              this.encoding = encoding;
69          }
70  
71          @Override
72          public Reader getReader() throws Exception {
73              BOMInputStream inputStream = 
74                  new BOMInputStream(new FileInputStream(file),
75                          ByteOrderMark.UTF_8, ByteOrderMark.UTF_16BE, ByteOrderMark.UTF_16LE);
76  
77              if (inputStream.hasBOM()) {
78                 encoding = inputStream.getBOMCharsetName();
79              }
80              return new InputStreamReader(inputStream, encoding);
81          }
82  
83          public String getEncoding() {
84              return encoding;
85          }
86  
87          @Override
88          public String getFileName() {
89              return file.getAbsolutePath();
90          }
91      }
92  
93      public static class StringCodeLoader extends CodeLoader {
94          public static final String DEFAULT_NAME = "CODE_LOADED_FROM_STRING";
95  
96          private String code;
97  
98          private String name;
99  
100         public StringCodeLoader(String code) {
101             this(code, DEFAULT_NAME);
102         }
103 
104         public StringCodeLoader(String code, String name) {
105             this.code = code;
106             this.name = name;
107         }
108 
109         @Override
110         public Reader getReader() {
111             return new StringReader(code);
112         }
113 
114         @Override
115         public String getFileName() {
116             return name;
117         }
118     }
119 
120     public static class ReaderCodeLoader extends CodeLoader {
121         public static final String DEFAULT_NAME = "CODE_LOADED_FROM_READER";
122 
123         private Reader code;
124 
125         private String name;
126 
127         public ReaderCodeLoader(Reader code) {
128             this(code, DEFAULT_NAME);
129         }
130 
131         public ReaderCodeLoader(Reader code, String name) {
132             this.code = code;
133             this.name = name;
134         }
135 
136         @Override
137         public Reader getReader() {
138             return code;
139         }
140 
141         @Override
142         public String getFileName() {
143             return name;
144         }
145     }
146 
147     private CodeLoader cl;
148 
149     public SourceCode(CodeLoader cl) {
150         this.cl = cl;
151     }
152 
153     public List<String> getCode() {
154         return cl.getCode();
155     }
156 
157     public StringBuilder getCodeBuffer() {
158         StringBuilder sb = new StringBuilder();
159         List<String> lines = cl.getCode();
160         for (String line : lines) {
161             sb.append(line).append(PMD.EOL);
162         }
163         return sb;
164     }
165 
166     public String getSlice(int startLine, int endLine) {
167         StringBuilder sb = new StringBuilder();
168         List<String> lines = cl.getCode();
169         for (int i = startLine == 0 ? startLine : startLine - 1; i < endLine && i < lines.size(); i++) {
170             if (sb.length() != 0) {
171                 sb.append(PMD.EOL);
172             }
173             sb.append(lines.get(i));
174         }
175         return sb.toString();
176     }
177 
178     public String getFileName() {
179         return cl.getFileName();
180     }
181 }