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 }