1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.shared.filtering;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.OutputStream;
24 import java.io.Reader;
25 import java.io.Writer;
26 import java.nio.charset.Charset;
27 import java.nio.file.Files;
28 import java.nio.file.NoSuchFileException;
29 import java.nio.file.attribute.PosixFilePermission;
30 import java.util.EnumSet;
31 import java.util.StringTokenizer;
32 import java.util.regex.Pattern;
33
34 import org.apache.commons.lang3.SystemUtils;
35 import org.codehaus.plexus.util.io.CachingOutputStream;
36 import org.codehaus.plexus.util.io.CachingWriter;
37
38
39
40
41
42 public final class FilteringUtils {
43
44
45
46 private static final int ONE_KB = 1024;
47
48
49
50
51 private static final int ONE_MB = ONE_KB * ONE_KB;
52
53
54
55
56 private static final int FILE_COPY_BUFFER_SIZE = ONE_MB * 30;
57
58 private static final String WINDOWS_PATH_PATTERN = "^(.*)[a-zA-Z]:\\\\(.*)";
59
60 private static final Pattern PATTERN = Pattern.compile(WINDOWS_PATH_PATTERN);
61 public static final int COPY_BUFFER_LENGTH = 8192;
62
63
64
65
66 private FilteringUtils() {
67
68 }
69
70
71
72
73
74
75
76 public static String escapeWindowsPath(String val) {
77 if (!isEmpty(val) && PATTERN.matcher(val).matches()) {
78
79 StringBuilder buf = new StringBuilder(val.length());
80 int start = 0, end = 0;
81 while ((end = val.indexOf('\\', start)) != -1) {
82 buf.append(val, start, end).append("\\\\");
83 start = end + 1;
84
85 if (val.indexOf('\\', end + 1) == end + 1) {
86 start++;
87 }
88 }
89
90 buf.append(val.substring(start));
91
92 return buf.toString();
93 }
94 return val;
95 }
96
97
98
99
100
101
102
103
104
105
106 public static File resolveFile(final File baseFile, String filename) {
107 String filenm = filename;
108 if ('/' != File.separatorChar) {
109 filenm = filename.replace('/', File.separatorChar);
110 }
111
112 if ('\\' != File.separatorChar) {
113 filenm = filename.replace('\\', File.separatorChar);
114 }
115
116
117 if (filenm.startsWith(File.separator) || (SystemUtils.IS_OS_WINDOWS && filenm.indexOf(":") > 0)) {
118 File file = new File(filenm);
119
120 try {
121 file = file.getCanonicalFile();
122 } catch (final IOException ioe) {
123
124 }
125
126 return file;
127 }
128
129
130 final char[] chars = filename.toCharArray();
131 final StringBuilder sb = new StringBuilder();
132
133
134
135
136 int start = 0;
137 if ('\\' == File.separatorChar) {
138 sb.append(filenm.charAt(0));
139 start++;
140 }
141
142 for (int i = start; i < chars.length; i++) {
143 final boolean doubleSeparator = File.separatorChar == chars[i] && File.separatorChar == chars[i - 1];
144
145 if (!doubleSeparator) {
146 sb.append(chars[i]);
147 }
148 }
149
150 filenm = sb.toString();
151
152
153 File file = (new File(baseFile, filenm)).getAbsoluteFile();
154
155 try {
156 file = file.getCanonicalFile();
157 } catch (final IOException ioe) {
158
159 }
160
161 return file;
162 }
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184 public static String getRelativeFilePath(final String oldPath, final String newPath) {
185 if (isEmpty(oldPath) || isEmpty(newPath)) {
186 return "";
187 }
188
189
190 String fromPath = new File(oldPath).getPath();
191 String toPath = new File(newPath).getPath();
192
193
194 if (toPath.matches("^\\[a-zA-Z]:")) {
195 toPath = toPath.substring(1);
196 }
197 if (fromPath.matches("^\\[a-zA-Z]:")) {
198 fromPath = fromPath.substring(1);
199 }
200
201
202 if (fromPath.startsWith(":", 1)) {
203 fromPath = Character.toLowerCase(fromPath.charAt(0)) + fromPath.substring(1);
204 }
205 if (toPath.startsWith(":", 1)) {
206 toPath = Character.toLowerCase(toPath.charAt(0)) + toPath.substring(1);
207 }
208
209
210
211 if ((toPath.startsWith(":", 1) && fromPath.startsWith(":", 1))
212 && (!toPath.substring(0, 1).equals(fromPath.substring(0, 1)))) {
213
214
215 return null;
216 }
217
218 if ((toPath.startsWith(":", 1) && !fromPath.startsWith(":", 1))
219 || (!toPath.startsWith(":", 1) && fromPath.startsWith(":", 1))) {
220
221
222 return null;
223 }
224
225 String resultPath = buildRelativePath(toPath, fromPath, File.separatorChar);
226
227 if (newPath.endsWith(File.separator) && !resultPath.endsWith(File.separator)) {
228 return resultPath + File.separator;
229 }
230
231 return resultPath;
232 }
233
234 private static String buildRelativePath(String toPath, String fromPath, final char separatorChar) {
235
236 StringTokenizer toTokeniser = new StringTokenizer(toPath, String.valueOf(separatorChar));
237 StringTokenizer fromTokeniser = new StringTokenizer(fromPath, String.valueOf(separatorChar));
238
239 int count = 0;
240
241
242 while (toTokeniser.hasMoreTokens() && fromTokeniser.hasMoreTokens()) {
243 if (separatorChar == '\\') {
244 if (!fromTokeniser.nextToken().equalsIgnoreCase(toTokeniser.nextToken())) {
245 break;
246 }
247 } else {
248 if (!fromTokeniser.nextToken().equals(toTokeniser.nextToken())) {
249 break;
250 }
251 }
252
253 count++;
254 }
255
256
257
258
259 toTokeniser = new StringTokenizer(toPath, String.valueOf(separatorChar));
260 fromTokeniser = new StringTokenizer(fromPath, String.valueOf(separatorChar));
261
262 while (count-- > 0) {
263 fromTokeniser.nextToken();
264 toTokeniser.nextToken();
265 }
266
267 StringBuilder relativePath = new StringBuilder();
268
269
270 while (fromTokeniser.hasMoreTokens()) {
271 fromTokeniser.nextToken();
272
273 relativePath.append("..");
274
275 if (fromTokeniser.hasMoreTokens()) {
276 relativePath.append(separatorChar);
277 }
278 }
279
280 if (relativePath.length() != 0 && toTokeniser.hasMoreTokens()) {
281 relativePath.append(separatorChar);
282 }
283
284
285 while (toTokeniser.hasMoreTokens()) {
286 relativePath.append(toTokeniser.nextToken());
287
288 if (toTokeniser.hasMoreTokens()) {
289 relativePath.append(separatorChar);
290 }
291 }
292 return relativePath.toString();
293 }
294
295 static boolean isEmpty(final String string) {
296 return string == null || string.trim().isEmpty();
297 }
298
299
300
301
302
303
304
305
306
307
308
309 public static void copyFile(File from, File to, String encoding, FilterWrapper[] wrappers) throws IOException {
310 setReadWritePermissions(to);
311
312 if (wrappers == null || wrappers.length == 0) {
313 try (OutputStream os = new CachingOutputStream(to.toPath())) {
314 Files.copy(from.toPath(), os);
315 }
316 } else {
317 Charset charset = charset(encoding);
318 try (Reader fileReader = Files.newBufferedReader(from.toPath(), charset)) {
319 Reader wrapped = fileReader;
320 for (FilterWrapper wrapper : wrappers) {
321 wrapped = wrapper.getReader(wrapped);
322 }
323 try (Writer writer = new CachingWriter(to.toPath(), charset)) {
324 char[] buffer = new char[COPY_BUFFER_LENGTH];
325 int nRead;
326 while ((nRead = wrapped.read(buffer, 0, COPY_BUFFER_LENGTH)) >= 0) {
327 writer.write(buffer, 0, nRead);
328 }
329 }
330 }
331 }
332
333 copyFilePermissions(from, to);
334 }
335
336
337
338
339
340
341
342
343
344
345
346
347
348 @Deprecated
349 public static void copyFile(File from, File to, String encoding, FilterWrapper[] wrappers, boolean overwrite)
350 throws IOException {
351 copyFile(from, to, encoding, wrappers);
352 }
353
354
355
356
357
358
359
360
361
362
363
364 private static void copyFilePermissions(File source, File destination) throws IOException {
365 try {
366
367 Files.setPosixFilePermissions(destination.toPath(), Files.getPosixFilePermissions(source.toPath()));
368 } catch (NoSuchFileException nsfe) {
369
370 } catch (UnsupportedOperationException e) {
371
372 destination.setExecutable(source.canExecute());
373 destination.setReadable(source.canRead());
374 destination.setWritable(source.canWrite());
375 }
376 }
377
378 @SuppressWarnings("ResultOfMethodCallIgnored")
379 private static void setReadWritePermissions(File file) throws IOException {
380 if (file.exists()) {
381 try {
382 Files.setPosixFilePermissions(
383 file.toPath(),
384 EnumSet.of(
385 PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE,
386 PosixFilePermission.GROUP_READ, PosixFilePermission.GROUP_WRITE,
387 PosixFilePermission.OTHERS_READ, PosixFilePermission.OTHERS_WRITE));
388 } catch (UnsupportedOperationException e) {
389 file.setReadable(true);
390 file.setWritable(true);
391 }
392 }
393 }
394
395 private static Charset charset(String encoding) {
396 if (encoding == null || encoding.isEmpty()) {
397 return Charset.defaultCharset();
398 } else {
399 return Charset.forName(encoding);
400 }
401 }
402 }