1
2
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 }