1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle.api;
21
22 import java.io.BufferedReader;
23 import java.io.File;
24 import java.io.FileNotFoundException;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.InputStreamReader;
28 import java.io.Reader;
29 import java.io.StringReader;
30 import java.nio.charset.Charset;
31 import java.nio.charset.CharsetDecoder;
32 import java.nio.charset.CodingErrorAction;
33 import java.nio.charset.UnsupportedCharsetException;
34 import java.nio.file.Files;
35 import java.util.ArrayList;
36 import java.util.Arrays;
37 import java.util.List;
38 import java.util.regex.Matcher;
39 import java.util.regex.Pattern;
40
41 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
42
43
44
45
46
47
48
49
50
51 public final class FileText {
52
53
54
55
56 private static final int READ_BUFFER_SIZE = 1024;
57
58
59
60
61 private static final Pattern LINE_TERMINATOR = Pattern.compile("\\n|\\r\\n?");
62
63
64
65
66
67
68
69
70
71
72 private final File file;
73
74
75
76
77
78 private final Charset charset;
79
80
81
82
83 private final String[] lines;
84
85
86
87
88
89
90
91
92 private String fullText;
93
94
95
96
97 private int[] lineBreaks;
98
99
100
101
102
103
104 public FileText" href="../../../../../com/puppycrawl/tools/checkstyle/api/FileText.html#FileText">FileText(FileText fileText) {
105 file = fileText.file;
106 charset = fileText.charset;
107 fullText = fileText.fullText;
108 lines = fileText.lines.clone();
109 if (fileText.lineBreaks == null) {
110 lineBreaks = null;
111 }
112 else {
113 lineBreaks = fileText.lineBreaks.clone();
114 }
115 }
116
117
118
119
120
121
122
123
124
125
126
127
128 public FileText(File file, List<String> lines) {
129 final StringBuilder buf = new StringBuilder(1024);
130 for (final String line : lines) {
131 buf.append(line).append('\n');
132 }
133
134 this.file = file;
135 charset = null;
136 fullText = buf.toString();
137 this.lines = lines.toArray(CommonUtil.EMPTY_STRING_ARRAY);
138 }
139
140
141
142
143
144
145
146
147
148
149
150
151
152 public FileText(File file, String charsetName) throws IOException {
153 this.file = file;
154
155
156
157 final CharsetDecoder decoder;
158 try {
159 charset = Charset.forName(charsetName);
160 decoder = charset.newDecoder();
161 decoder.onMalformedInput(CodingErrorAction.REPLACE);
162 decoder.onUnmappableCharacter(CodingErrorAction.REPLACE);
163 }
164 catch (final UnsupportedCharsetException ex) {
165 final String message = "Unsupported charset: " + charsetName;
166 throw new IllegalStateException(message, ex);
167 }
168
169 fullText = readFile(file, decoder);
170
171
172
173
174 try (BufferedReader reader = new BufferedReader(new StringReader(fullText))) {
175 final ArrayList<String> textLines = new ArrayList<>();
176 while (true) {
177 final String line = reader.readLine();
178 if (line == null) {
179 break;
180 }
181 textLines.add(line);
182 }
183 lines = textLines.toArray(CommonUtil.EMPTY_STRING_ARRAY);
184 }
185 }
186
187
188
189
190
191
192
193
194
195
196 private static String readFile(final File inputFile, final CharsetDecoder decoder)
197 throws IOException {
198 if (!inputFile.exists()) {
199 throw new FileNotFoundException(inputFile.getPath() + " (No such file or directory)");
200 }
201 final StringBuilder buf = new StringBuilder(1024);
202 final InputStream stream = Files.newInputStream(inputFile.toPath());
203 try (Reader reader = new InputStreamReader(stream, decoder)) {
204 final char[] chars = new char[READ_BUFFER_SIZE];
205 while (true) {
206 final int len = reader.read(chars);
207 if (len == -1) {
208 break;
209 }
210 buf.append(chars, 0, len);
211 }
212 }
213 return buf.toString();
214 }
215
216
217
218
219
220
221
222
223 public String get(final int lineNo) {
224 return lines[lineNo];
225 }
226
227
228
229
230
231
232 public File getFile() {
233 return file;
234 }
235
236
237
238
239
240
241
242 public Charset getCharset() {
243 return charset;
244 }
245
246
247
248
249
250
251 public CharSequence getFullText() {
252 return fullText;
253 }
254
255
256
257
258
259
260
261
262 public String[] toLinesArray() {
263 return lines.clone();
264 }
265
266
267
268
269
270
271
272 public LineColumn lineColumn(int pos) {
273 final int[] lineBreakPositions = findLineBreaks();
274 int lineNo = Arrays.binarySearch(lineBreakPositions, pos);
275 if (lineNo < 0) {
276
277
278 lineNo = -lineNo - 2;
279 }
280 final int startOfLine = lineBreakPositions[lineNo];
281 final int columnNo = pos - startOfLine;
282
283 return new LineColumn(lineNo + 1, columnNo);
284 }
285
286
287
288
289
290
291 private int[] findLineBreaks() {
292 if (lineBreaks == null) {
293 final int[] lineBreakPositions = new int[size() + 1];
294 lineBreakPositions[0] = 0;
295 int lineNo = 1;
296 final Matcher matcher = LINE_TERMINATOR.matcher(fullText);
297 while (matcher.find()) {
298 lineBreakPositions[lineNo] = matcher.end();
299 lineNo++;
300 }
301 if (lineNo < lineBreakPositions.length) {
302 lineBreakPositions[lineNo] = fullText.length();
303 }
304 lineBreaks = lineBreakPositions;
305 }
306 return lineBreaks;
307 }
308
309
310
311
312
313
314 public int size() {
315 return lines.length;
316 }
317
318 }