1 /*
2 * SmartSprites Project
3 *
4 * Copyright (C) 2007-2009, Stanisław Osiński.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without modification,
8 * are permitted provided that the following conditions are met:
9 *
10 * - Redistributions of source code must retain the above copyright notice, this
11 * list of conditions and the following disclaimer.
12 *
13 * - Redistributions in binary form must reproduce the above copyright notice, this
14 * list of conditions and the following disclaimer in the documentation and/or
15 * other materials provided with the distribution.
16 *
17 * - Neither the name of the SmartSprites Project nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * - We kindly request that you include in the end-user documentation provided with
22 * the redistribution and/or in the software itself an acknowledgement equivalent
23 * to the following: "This product includes software developed by the SmartSprites
24 * Project."
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
30 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
33 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37 package org.carrot2.util;
38
39 import java.io.File;
40 import java.io.IOException;
41 import java.util.ArrayList;
42 import java.util.regex.Pattern;
43
44 import org.apache.commons.io.FilenameUtils;
45
46 /**
47 * Various utility methods for working with {@link File}s.
48 */
49 public class FileUtils {
50
51 /**
52 * Instantiates a new file utils.
53 */
54 private FileUtils() {
55 // Prevent Instantiation
56 }
57
58 /**
59 * Creates a new {@link File} from the provided path and attempts to execute {@link File#getCanonicalFile()}. In
60 * case of a failure, returns the result of {@link File#getAbsoluteFile()}.
61 *
62 * @param path
63 * the path
64 *
65 * @return the canonical or absolute file
66 */
67 public static File getCanonicalOrAbsoluteFile(String path) {
68 File file = new File(path);
69 try {
70 return file.getCanonicalFile();
71 } catch (final IOException e) {
72 return file.getAbsoluteFile();
73 }
74 }
75
76 /**
77 * Changes the root directory of a file. For example, file is /a/b/c/d/e and oldRoot is /a/b/c, and newRoot is /x/y,
78 * the result will be /x/y/d/e.
79 *
80 * @param file
81 * the file
82 * @param oldRoot
83 * the old root
84 * @param newRoot
85 * the new root
86 *
87 * @return the string
88 */
89 public static String changeRoot(String file, String oldRoot, String newRoot) {
90 // File is assumed to be a subpath of oldRoot, so PathUtils.getRelativeFilePath()
91 // shouldn't return null here.
92 final String relativePath = PathUtils.getRelativeFilePath(oldRoot, file);
93 return FilenameUtils.concat(newRoot, relativePath);
94 }
95
96 /**
97 * Removes useless segments in relative paths, e.g. replaces <code>../path/../other/file.css</code> with
98 * <code>../other/file.css</code>
99 *
100 * @param path
101 * the path
102 * @param separator
103 * the separator
104 *
105 * @return the string
106 */
107 public static String canonicalize(String path, String separator) {
108 String replaced = path;
109 String toReplace = null;
110 final String separatorEscaped = Pattern.quote(separator);
111 final Pattern pattern = Pattern
112 .compile("[^" + separatorEscaped + "\\.]+" + separatorEscaped + "\\.\\." + separatorEscaped + "?");
113 while (!replaced.equals(toReplace)) {
114 toReplace = replaced;
115 replaced = pattern.matcher(toReplace).replaceFirst("");
116 }
117 return replaced;
118 }
119
120 /**
121 * Attempts to delete the provided files and throws an {@link IOException} in case {@link File#delete()} returns
122 * <code>false</code> for any of them.
123 *
124 * @param files
125 * the files
126 *
127 * @throws IOException
128 * Signals that an I/O exception has occurred.
129 */
130 public static void deleteThrowingExceptions(File... files) throws IOException {
131 if (files == null) {
132 return;
133 }
134
135 final ArrayList<String> undeletedFiles = new ArrayList<>();
136 for (File file : files) {
137 if (file == null) {
138 continue;
139 }
140
141 if (file.exists() && !file.delete()) {
142 undeletedFiles.add(file.getPath());
143 }
144 }
145
146 if (!undeletedFiles.isEmpty()) {
147 throw new IOException("Unable to delete files: " + undeletedFiles.toString());
148 }
149 }
150
151 /**
152 * Calls {@link File#mkdirs()} on the provided argument and throws an {@link IOException} if the call returns
153 * <code>false</code>.
154 *
155 * @param dirs
156 * the dirs
157 *
158 * @throws IOException
159 * Signals that an I/O exception has occurred.
160 */
161 public static void mkdirsThrowingExceptions(File dirs) throws IOException {
162 if (dirs.exists()) {
163 return;
164 }
165
166 if (!dirs.mkdirs()) {
167 throw new IOException("Unable to create directories: " + dirs.getPath());
168 }
169 }
170
171 /**
172 * Returns <code>true</code> if file is contained in the parent directory or any parent of the parent directory.
173 *
174 * @param file
175 * the file
176 * @param parent
177 * the parent
178 *
179 * @return true, if is file in parent
180 */
181 public static boolean isFileInParent(File file, File parent) {
182 final File fileParent = file.getParentFile();
183 if (fileParent == null) {
184 return false;
185 }
186
187 if (fileParent.equals(parent)) {
188 return true;
189 }
190
191 return isFileInParent(fileParent, parent);
192 }
193 }