diff options
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FileUtils.java')
-rw-r--r-- | framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FileUtils.java | 1722 |
1 files changed, 0 insertions, 1722 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FileUtils.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FileUtils.java deleted file mode 100644 index bcef5ecf..00000000 --- a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FileUtils.java +++ /dev/null @@ -1,1722 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ -package org.apache.tools.ant.util; - -import java.io.File; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.Reader; -import java.io.Writer; -import java.net.HttpURLConnection; -import java.net.JarURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLConnection; -import java.nio.channels.Channel; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.Random; -import java.util.Stack; -import java.util.StringTokenizer; -import java.util.Vector; -import java.util.jar.JarFile; - -import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.PathTokenizer; -import org.apache.tools.ant.Project; -import org.apache.tools.ant.launch.Locator; -import org.apache.tools.ant.taskdefs.condition.Os; -import org.apache.tools.ant.types.FilterSetCollection; -import org.apache.tools.ant.types.resources.FileResource; - -/** - * This class also encapsulates methods which allow Files to be - * referred to using abstract path names which are translated to native - * system file paths at runtime as well as copying files or setting - * their last modification time. - * - */ -public class FileUtils { - private static final int DELETE_RETRY_SLEEP_MILLIS = 10; - private static final int EXPAND_SPACE = 50; - private static final FileUtils PRIMARY_INSTANCE = new FileUtils(); - - //get some non-crypto-grade randomness from various places. - private static Random rand = new Random(System.currentTimeMillis() - + Runtime.getRuntime().freeMemory()); - - private static final boolean ON_NETWARE = Os.isFamily("netware"); - private static final boolean ON_DOS = Os.isFamily("dos"); - private static final boolean ON_WIN9X = Os.isFamily("win9x"); - private static final boolean ON_WINDOWS = Os.isFamily("windows"); - - static final int BUF_SIZE = 8192; - - - /** - * The granularity of timestamps under FAT. - */ - public static final long FAT_FILE_TIMESTAMP_GRANULARITY = 2000; - - /** - * The granularity of timestamps under Unix. - */ - public static final long UNIX_FILE_TIMESTAMP_GRANULARITY = 1000; - - /** - * The granularity of timestamps under the NT File System. - * NTFS has a granularity of 100 nanoseconds, which is less - * than 1 millisecond, so we round this up to 1 millisecond. - */ - public static final long NTFS_FILE_TIMESTAMP_GRANULARITY = 1; - - /** - * A one item cache for fromUri. - * fromUri is called for each element when parseing ant build - * files. It is a costly operation. This just caches the result - * of the last call. - */ - private Object cacheFromUriLock = new Object(); - private String cacheFromUriRequest = null; - private String cacheFromUriResponse = null; - - /** - * Factory method. - * - * @return a new instance of FileUtils. - * @deprecated since 1.7. - * Use getFileUtils instead, - * FileUtils do not have state. - */ - public static FileUtils newFileUtils() { - return new FileUtils(); - } - - /** - * Method to retrieve The FileUtils, which is shared by all users of this - * method. - * @return an instance of FileUtils. - * @since Ant 1.6.3 - */ - public static FileUtils getFileUtils() { - return PRIMARY_INSTANCE; - } - - /** - * Empty constructor. - */ - protected FileUtils() { - } - - /** - * Get the URL for a file taking into account # characters. - * - * @param file the file whose URL representation is required. - * @return The FileURL value. - * @throws MalformedURLException if the URL representation cannot be - * formed. - */ - public URL getFileURL(File file) throws MalformedURLException { - return new URL(file.toURI().toASCIIString()); - } - - /** - * Convenience method to copy a file from a source to a destination. - * No filtering is performed. - * - * @param sourceFile Name of file to copy from. - * Must not be <code>null</code>. - * @param destFile Name of file to copy to. - * Must not be <code>null</code>. - * - * @throws IOException if the copying fails. - */ - public void copyFile(String sourceFile, String destFile) throws IOException { - copyFile(new File(sourceFile), new File(destFile), null, false, false); - } - - /** - * Convenience method to copy a file from a source to a destination - * specifying if token filtering must be used. - * - * @param sourceFile Name of file to copy from. - * Must not be <code>null</code>. - * @param destFile Name of file to copy to. - * Must not be <code>null</code>. - * @param filters the collection of filters to apply to this copy. - * - * @throws IOException if the copying fails. - */ - public void copyFile(String sourceFile, String destFile, FilterSetCollection filters) - throws IOException { - copyFile(new File(sourceFile), new File(destFile), filters, false, false); - } - - /** - * Convenience method to copy a file from a source to a destination specifying if token - * filtering must be used and if source files may overwrite newer destination files. - * - * @param sourceFile Name of file to copy from. Must not be <code>null</code>. - * @param destFile Name of file to copy to. Must not be <code>null</code>. - * @param filters the collection of filters to apply to this copy. - * @param overwrite Whether or not the destination file should be overwritten if it already - * exists. - * - * @throws IOException if the copying fails. - */ - public void copyFile(String sourceFile, String destFile, FilterSetCollection filters, - boolean overwrite) throws IOException { - copyFile(new File(sourceFile), new File(destFile), filters, overwrite, false); - } - - /** - * Convenience method to copy a file from a source to a destination - * specifying if token - * filtering must be used, if source files may overwrite newer destination - * files and the last - * modified time of <code>destFile</code> file should be made equal to - * the last modified time - * of <code>sourceFile</code>. - * - * @param sourceFile Name of file to copy from. Must not be <code>null</code>. - * @param destFile Name of file to copy to. Must not be <code>null</code>. - * @param filters the collection of filters to apply to this copy. - * @param overwrite Whether or not the destination file should be - * overwritten if it already exists. - * @param preserveLastModified Whether or not the last modified time of - * the resulting file - * should be set to that of the source file. - * - * @throws IOException if the copying fails. - */ - public void copyFile(String sourceFile, String destFile, - FilterSetCollection filters, - boolean overwrite, boolean preserveLastModified) - throws IOException { - copyFile(new File(sourceFile), new File(destFile), filters, overwrite, - preserveLastModified); - } - - /** - * Convenience method to copy a file from a source to a destination specifying if token - * filtering must be used, if source files may overwrite newer destination files and the last - * modified time of <code>destFile</code> file should be made equal to the last modified time - * of <code>sourceFile</code>. - * - * @param sourceFile Name of file to copy from. Must not be <code>null</code>. - * @param destFile Name of file to copy to. Must not be <code>null</code>. - * @param filters the collection of filters to apply to this copy. - * @param overwrite Whether or not the destination file should be overwritten if it already - * exists. - * @param preserveLastModified Whether or not the last modified time of the resulting file - * should be set to that of the source file. - * @param encoding the encoding used to read and write the files. - * - * @throws IOException if the copying fails. - * - * @since Ant 1.5 - */ - public void copyFile(String sourceFile, String destFile, - FilterSetCollection filters, boolean overwrite, - boolean preserveLastModified, String encoding) throws IOException { - copyFile(new File(sourceFile), new File(destFile), filters, - overwrite, preserveLastModified, encoding); - } - - // CheckStyle:ParameterNumberCheck OFF - bc - /** - * Convenience method to copy a file from a source to a - * destination specifying if token filtering must be used, if - * filter chains must be used, if source files may overwrite - * newer destination files and the last modified time of - * <code>destFile</code> file should be made equal - * to the last modified time of <code>sourceFile</code>. - * - * @param sourceFile Name of file to copy from. - * Must not be <code>null</code>. - * @param destFile Name of file to copy to. - * Must not be <code>null</code>. - * @param filters the collection of filters to apply to this copy. - * @param filterChains filterChains to apply during the copy. - * @param overwrite Whether or not the destination file should be - * overwritten if it already exists. - * @param preserveLastModified Whether or not the last modified time of - * the resulting file should be set to that - * of the source file. - * @param encoding the encoding used to read and write the files. - * @param project the project instance. - * - * @throws IOException if the copying fails. - * - * @since Ant 1.5 - */ - public void copyFile(String sourceFile, String destFile, - FilterSetCollection filters, Vector filterChains, - boolean overwrite, boolean preserveLastModified, - String encoding, Project project) throws IOException { - copyFile(new File(sourceFile), new File(destFile), filters, filterChains, overwrite, - preserveLastModified, encoding, project); - } - - /** - * Convenience method to copy a file from a source to a destination specifying if token - * filtering must be used, if filter chains must be used, if source files may overwrite newer - * destination files and the last modified time of <code>destFile</code> file should be made - * equal to the last modified time of <code>sourceFile</code>. - * - * @param sourceFile Name of file to copy from. Must not be <code>null</code>. - * @param destFile Name of file to copy to. Must not be <code>null</code>. - * @param filters the collection of filters to apply to this copy. - * @param filterChains filterChains to apply during the copy. - * @param overwrite Whether or not the destination file should be overwritten if it already - * exists. - * @param preserveLastModified Whether or not the last modified time of the resulting file - * should be set to that of the source file. - * @param inputEncoding the encoding used to read the files. - * @param outputEncoding the encoding used to write the files. - * @param project the project instance. - * - * @throws IOException if the copying fails. - * - * @since Ant 1.6 - */ - public void copyFile(String sourceFile, String destFile, - FilterSetCollection filters, Vector filterChains, - boolean overwrite, boolean preserveLastModified, - String inputEncoding, String outputEncoding, - Project project) throws IOException { - copyFile(new File(sourceFile), new File(destFile), filters, filterChains, overwrite, - preserveLastModified, inputEncoding, outputEncoding, project); - } - - /** - * Convenience method to copy a file from a source to a destination. No filtering is performed. - * - * @param sourceFile the file to copy from. Must not be <code>null</code>. - * @param destFile the file to copy to. Must not be <code>null</code>. - * - * @throws IOException if the copying fails. - */ - public void copyFile(File sourceFile, File destFile) throws IOException { - copyFile(sourceFile, destFile, null, false, false); - } - - /** - * Convenience method to copy a file from a source to a destination - * specifying if token filtering must be used. - * - * @param sourceFile the file to copy from. - * Must not be <code>null</code>. - * @param destFile the file to copy to. - * Must not be <code>null</code>. - * @param filters the collection of filters to apply to this copy. - * - * @throws IOException if the copying fails. - */ - public void copyFile(File sourceFile, File destFile, FilterSetCollection filters) - throws IOException { - copyFile(sourceFile, destFile, filters, false, false); - } - - /** - * Convenience method to copy a file from a source to a - * destination specifying if token filtering must be used and if - * source files may overwrite newer destination files. - * - * @param sourceFile the file to copy from. - * Must not be <code>null</code>. - * @param destFile the file to copy to. - * Must not be <code>null</code>. - * @param filters the collection of filters to apply to this copy. - * @param overwrite Whether or not the destination file should be - * overwritten if it already exists. - * - * @throws IOException if the copying fails. - */ - public void copyFile(File sourceFile, File destFile, FilterSetCollection filters, - boolean overwrite) throws IOException { - copyFile(sourceFile, destFile, filters, overwrite, false); - } - - /** - * Convenience method to copy a file from a source to a - * destination specifying if token filtering must be used, if - * source files may overwrite newer destination files and the - * last modified time of <code>destFile</code> file should be made equal - * to the last modified time of <code>sourceFile</code>. - * - * @param sourceFile the file to copy from. - * Must not be <code>null</code>. - * @param destFile the file to copy to. - * Must not be <code>null</code>. - * @param filters the collection of filters to apply to this copy. - * @param overwrite Whether or not the destination file should be - * overwritten if it already exists. - * @param preserveLastModified Whether or not the last modified time of - * the resulting file should be set to that - * of the source file. - * - * @throws IOException if the copying fails. - */ - public void copyFile(File sourceFile, File destFile, FilterSetCollection filters, - boolean overwrite, boolean preserveLastModified) throws IOException { - copyFile(sourceFile, destFile, filters, overwrite, preserveLastModified, null); - } - - /** - * Convenience method to copy a file from a source to a destination specifying if token - * filtering must be used, if source files may overwrite newer destination files, the last - * modified time of <code>destFile</code> file should be made equal to the last modified time - * of <code>sourceFile</code> and which character encoding to assume. - * - * @param sourceFile the file to copy from. Must not be <code>null</code>. - * @param destFile the file to copy to. Must not be <code>null</code>. - * @param filters the collection of filters to apply to this copy. - * @param overwrite Whether or not the destination file should be overwritten if it already - * exists. - * @param preserveLastModified Whether or not the last modified time of the resulting file - * should be set to that of the source file. - * @param encoding the encoding used to read and write the files. - * - * @throws IOException if the copying fails. - * - * @since Ant 1.5 - */ - public void copyFile(File sourceFile, File destFile, - FilterSetCollection filters, boolean overwrite, - boolean preserveLastModified, String encoding) throws IOException { - copyFile(sourceFile, destFile, filters, null, overwrite, - preserveLastModified, encoding, null); - } - - /** - * Convenience method to copy a file from a source to a - * destination specifying if token filtering must be used, if - * filter chains must be used, if source files may overwrite - * newer destination files and the last modified time of - * <code>destFile</code> file should be made equal - * to the last modified time of <code>sourceFile</code>. - * - * @param sourceFile the file to copy from. - * Must not be <code>null</code>. - * @param destFile the file to copy to. - * Must not be <code>null</code>. - * @param filters the collection of filters to apply to this copy. - * @param filterChains filterChains to apply during the copy. - * @param overwrite Whether or not the destination file should be - * overwritten if it already exists. - * @param preserveLastModified Whether or not the last modified time of - * the resulting file should be set to that - * of the source file. - * @param encoding the encoding used to read and write the files. - * @param project the project instance. - * - * @throws IOException if the copying fails. - * - * @since Ant 1.5 - */ - public void copyFile(File sourceFile, File destFile, - FilterSetCollection filters, Vector filterChains, - boolean overwrite, boolean preserveLastModified, - String encoding, Project project) throws IOException { - copyFile(sourceFile, destFile, filters, filterChains, - overwrite, preserveLastModified, encoding, encoding, project); - } - - /** - * Convenience method to copy a file from a source to a - * destination specifying if token filtering must be used, if - * filter chains must be used, if source files may overwrite - * newer destination files and the last modified time of - * <code>destFile</code> file should be made equal - * to the last modified time of <code>sourceFile</code>. - * - * @param sourceFile the file to copy from. - * Must not be <code>null</code>. - * @param destFile the file to copy to. - * Must not be <code>null</code>. - * @param filters the collection of filters to apply to this copy. - * @param filterChains filterChains to apply during the copy. - * @param overwrite Whether or not the destination file should be - * overwritten if it already exists. - * @param preserveLastModified Whether or not the last modified time of - * the resulting file should be set to that - * of the source file. - * @param inputEncoding the encoding used to read the files. - * @param outputEncoding the encoding used to write the files. - * @param project the project instance. - * - * - * @throws IOException if the copying fails. - * - * @since Ant 1.6 - */ - public void copyFile(File sourceFile, File destFile, - FilterSetCollection filters, Vector filterChains, - boolean overwrite, boolean preserveLastModified, - String inputEncoding, String outputEncoding, - Project project) throws IOException { - copyFile(sourceFile, destFile, filters, filterChains, overwrite, preserveLastModified, - false, inputEncoding, outputEncoding, project); - } - - /** - * Convenience method to copy a file from a source to a - * destination specifying if token filtering must be used, if - * filter chains must be used, if source files may overwrite - * newer destination files and the last modified time of - * <code>destFile</code> file should be made equal - * to the last modified time of <code>sourceFile</code>. - * - * @param sourceFile the file to copy from. - * Must not be <code>null</code>. - * @param destFile the file to copy to. - * Must not be <code>null</code>. - * @param filters the collection of filters to apply to this copy. - * @param filterChains filterChains to apply during the copy. - * @param overwrite Whether or not the destination file should be - * overwritten if it already exists. - * @param preserveLastModified Whether or not the last modified time of - * the resulting file should be set to that - * of the source file. - * @param append whether to append to the destination file. - * @param inputEncoding the encoding used to read the files. - * @param outputEncoding the encoding used to write the files. - * @param project the project instance. - * - * - * @throws IOException if the copying fails. - * - * @since Ant 1.8 - */ - public void copyFile(File sourceFile, File destFile, - FilterSetCollection filters, Vector filterChains, - boolean overwrite, boolean preserveLastModified, - boolean append, - String inputEncoding, String outputEncoding, - Project project) throws IOException { - copyFile(sourceFile, destFile, filters, filterChains, overwrite, - preserveLastModified, append, inputEncoding, outputEncoding, - project, /* force: */ false); - } - - /** - * Convenience method to copy a file from a source to a - * destination specifying if token filtering must be used, if - * filter chains must be used, if source files may overwrite - * newer destination files and the last modified time of - * <code>destFile</code> file should be made equal - * to the last modified time of <code>sourceFile</code>. - * - * @param sourceFile the file to copy from. - * Must not be <code>null</code>. - * @param destFile the file to copy to. - * Must not be <code>null</code>. - * @param filters the collection of filters to apply to this copy. - * @param filterChains filterChains to apply during the copy. - * @param overwrite Whether or not the destination file should be - * overwritten if it already exists. - * @param preserveLastModified Whether or not the last modified time of - * the resulting file should be set to that - * of the source file. - * @param append whether to append to the destination file. - * @param inputEncoding the encoding used to read the files. - * @param outputEncoding the encoding used to write the files. - * @param project the project instance. - * @param force whether to overwrite read-only destination files. - * - * @throws IOException if the copying fails. - * - * @since Ant 1.8.2 - */ - public void copyFile(File sourceFile, File destFile, - FilterSetCollection filters, Vector filterChains, - boolean overwrite, boolean preserveLastModified, - boolean append, - String inputEncoding, String outputEncoding, - Project project, boolean force) throws IOException { - ResourceUtils.copyResource(new FileResource(sourceFile), - new FileResource(destFile), - filters, filterChains, overwrite, - preserveLastModified, append, inputEncoding, - outputEncoding, project, force); - } - - // CheckStyle:ParameterNumberCheck ON - - /** - * Calls File.setLastModified(long time). Originally written to - * to dynamically bind to that call on Java1.2+. - * - * @param file the file whose modified time is to be set - * @param time the time to which the last modified time is to be set. - * if this is -1, the current time is used. - */ - public void setFileLastModified(File file, long time) { - ResourceUtils.setLastModified(new FileResource(file), time); - } - - /** - * Interpret the filename as a file relative to the given file - * unless the filename already represents an absolute filename. - * Differs from <code>new File(file, filename)</code> in that - * the resulting File's path will always be a normalized, - * absolute pathname. Also, if it is determined that - * <code>filename</code> is context-relative, <code>file</code> - * will be discarded and the reference will be resolved using - * available context/state information about the filesystem. - * - * @param file the "reference" file for relative paths. This - * instance must be an absolute file and must not contain - * "./" or "../" sequences (same for \ instead - * of /). If it is null, this call is equivalent to - * <code>new java.io.File(filename).getAbsoluteFile()</code>. - * - * @param filename a file name. - * - * @return an absolute file. - * @throws java.lang.NullPointerException if filename is null. - */ - public File resolveFile(File file, String filename) { - if (!isAbsolutePath(filename)) { - char sep = File.separatorChar; - filename = filename.replace('/', sep).replace('\\', sep); - if (isContextRelativePath(filename)) { - file = null; - // on cygwin, our current directory can be a UNC; - // assume user.dir is absolute or all hell breaks loose... - String udir = System.getProperty("user.dir"); - if (filename.charAt(0) == sep && udir.charAt(0) == sep) { - filename = dissect(udir)[0] + filename.substring(1); - } - } - filename = new File(file, filename).getAbsolutePath(); - } - return normalize(filename); - } - - /** - * On DOS and NetWare, the evaluation of certain file - * specifications is context-dependent. These are filenames - * beginning with a single separator (relative to current root directory) - * and filenames with a drive specification and no intervening separator - * (relative to current directory of the specified root). - * @param filename the filename to evaluate. - * @return true if the filename is relative to system context. - * @throws java.lang.NullPointerException if filename is null. - * @since Ant 1.7 - */ - public static boolean isContextRelativePath(String filename) { - if (!(ON_DOS || ON_NETWARE) || filename.length() == 0) { - return false; - } - char sep = File.separatorChar; - filename = filename.replace('/', sep).replace('\\', sep); - char c = filename.charAt(0); - int len = filename.length(); - return (c == sep && (len == 1 || filename.charAt(1) != sep)) - || (Character.isLetter(c) && len > 1 - && filename.charAt(1) == ':' - && (len == 2 || filename.charAt(2) != sep)); - } - - /** - * Verifies that the specified filename represents an absolute path. - * Differs from new java.io.File("filename").isAbsolute() in that a path - * beginning with a double file separator--signifying a Windows UNC--must - * at minimum match "\\a\b" to be considered an absolute path. - * @param filename the filename to be checked. - * @return true if the filename represents an absolute path. - * @throws java.lang.NullPointerException if filename is null. - * @since Ant 1.6.3 - */ - public static boolean isAbsolutePath(String filename) { - int len = filename.length(); - if (len == 0) { - return false; - } - char sep = File.separatorChar; - filename = filename.replace('/', sep).replace('\\', sep); - char c = filename.charAt(0); - if (!(ON_DOS || ON_NETWARE)) { - return (c == sep); - } - if (c == sep) { - // CheckStyle:MagicNumber OFF - if (!(ON_DOS && len > 4 && filename.charAt(1) == sep)) { - return false; - } - // CheckStyle:MagicNumber ON - int nextsep = filename.indexOf(sep, 2); - return nextsep > 2 && nextsep + 1 < len; - } - int colon = filename.indexOf(':'); - return (Character.isLetter(c) && colon == 1 - && filename.length() > 2 && filename.charAt(2) == sep) - || (ON_NETWARE && colon > 0); - } - - /** - * Translate a path into its native (platform specific) format. - * <p> - * This method uses PathTokenizer to separate the input path - * into its components. This handles DOS style paths in a relatively - * sensible way. The file separators are then converted to their platform - * specific versions. - * - * @param toProcess The path to be translated. - * May be <code>null</code>. - * - * @return the native version of the specified path or - * an empty string if the path is <code>null</code> or empty. - * - * @since ant 1.7 - * @see PathTokenizer - */ - public static String translatePath(String toProcess) { - if (toProcess == null || toProcess.length() == 0) { - return ""; - } - StringBuffer path = new StringBuffer(toProcess.length() + EXPAND_SPACE); - PathTokenizer tokenizer = new PathTokenizer(toProcess); - while (tokenizer.hasMoreTokens()) { - String pathComponent = tokenizer.nextToken(); - pathComponent = pathComponent.replace('/', File.separatorChar); - pathComponent = pathComponent.replace('\\', File.separatorChar); - if (path.length() != 0) { - path.append(File.pathSeparatorChar); - } - path.append(pathComponent); - } - return path.toString(); - } - - /** - * "Normalize" the given absolute path. - * - * <p>This includes: - * <ul> - * <li>Uppercase the drive letter if there is one.</li> - * <li>Remove redundant slashes after the drive spec.</li> - * <li>Resolve all ./, .\, ../ and ..\ sequences.</li> - * <li>DOS style paths that start with a drive letter will have - * \ as the separator.</li> - * </ul> - * Unlike {@link File#getCanonicalPath()} this method - * specifically does not resolve symbolic links. - * - * @param path the path to be normalized. - * @return the normalized version of the path. - * - * @throws java.lang.NullPointerException if path is null. - */ - public File normalize(final String path) { - Stack s = new Stack(); - String[] dissect = dissect(path); - s.push(dissect[0]); - - StringTokenizer tok = new StringTokenizer(dissect[1], File.separator); - while (tok.hasMoreTokens()) { - String thisToken = tok.nextToken(); - if (".".equals(thisToken)) { - continue; - } - if ("..".equals(thisToken)) { - if (s.size() < 2) { - // Cannot resolve it, so skip it. - return new File(path); - } - s.pop(); - } else { // plain component - s.push(thisToken); - } - } - StringBuffer sb = new StringBuffer(); - final int size = s.size(); - for (int i = 0; i < size; i++) { - if (i > 1) { - // not before the filesystem root and not after it, since root - // already contains one - sb.append(File.separatorChar); - } - sb.append(s.elementAt(i)); - } - return new File(sb.toString()); - } - - /** - * Dissect the specified absolute path. - * @param path the path to dissect. - * @return String[] {root, remaining path}. - * @throws java.lang.NullPointerException if path is null. - * @since Ant 1.7 - */ - public String[] dissect(String path) { - char sep = File.separatorChar; - path = path.replace('/', sep).replace('\\', sep); - - // make sure we are dealing with an absolute path - if (!isAbsolutePath(path)) { - throw new BuildException(path + " is not an absolute path"); - } - String root = null; - int colon = path.indexOf(':'); - if (colon > 0 && (ON_DOS || ON_NETWARE)) { - - int next = colon + 1; - root = path.substring(0, next); - char[] ca = path.toCharArray(); - root += sep; - //remove the initial separator; the root has it. - next = (ca[next] == sep) ? next + 1 : next; - - StringBuffer sbPath = new StringBuffer(); - // Eliminate consecutive slashes after the drive spec: - for (int i = next; i < ca.length; i++) { - if (ca[i] != sep || ca[i - 1] != sep) { - sbPath.append(ca[i]); - } - } - path = sbPath.toString(); - } else if (path.length() > 1 && path.charAt(1) == sep) { - // UNC drive - int nextsep = path.indexOf(sep, 2); - nextsep = path.indexOf(sep, nextsep + 1); - root = (nextsep > 2) ? path.substring(0, nextsep + 1) : path; - path = path.substring(root.length()); - } else { - root = File.separator; - path = path.substring(1); - } - return new String[] {root, path}; - } - - /** - * Returns a VMS String representation of a <code>File</code> object. - * This is useful since the JVM by default internally converts VMS paths - * to Unix style. - * The returned String is always an absolute path. - * - * @param f The <code>File</code> to get the VMS path for. - * @return The absolute VMS path to <code>f</code>. - */ - public String toVMSPath(File f) { - // format: "DEVICE:[DIR.SUBDIR]FILE" - String osPath; - String path = normalize(f.getAbsolutePath()).getPath(); - String name = f.getName(); - boolean isAbsolute = path.charAt(0) == File.separatorChar; - // treat directories specified using .DIR syntax as files - // CheckStyle:MagicNumber OFF - boolean isDirectory = f.isDirectory() - && !name.regionMatches(true, name.length() - 4, ".DIR", 0, 4); - // CheckStyle:MagicNumber ON - String device = null; - StringBuffer directory = null; - String file = null; - - int index = 0; - - if (isAbsolute) { - index = path.indexOf(File.separatorChar, 1); - if (index == -1) { - return path.substring(1) + ":[000000]"; - } - device = path.substring(1, index++); - } - if (isDirectory) { - directory = new StringBuffer(path.substring(index).replace(File.separatorChar, '.')); - } else { - int dirEnd = path.lastIndexOf(File.separatorChar, path.length()); - if (dirEnd == -1 || dirEnd < index) { - file = path.substring(index); - } else { - directory = new StringBuffer(path.substring(index, dirEnd). - replace(File.separatorChar, '.')); - index = dirEnd + 1; - if (path.length() > index) { - file = path.substring(index); - } - } - } - if (!isAbsolute && directory != null) { - directory.insert(0, '.'); - } - osPath = ((device != null) ? device + ":" : "") - + ((directory != null) ? "[" + directory + "]" : "") - + ((file != null) ? file : ""); - return osPath; - } - - /** - * Create a File object for a temporary file in a given directory. Without - * actually creating the file. - * - * <p> - * The file denoted by the returned abstract pathname did not exist before - * this method was invoked, any subsequent invocation of this method will - * yield a different file name. - * </p> - * <p> - * The filename is prefixNNNNNsuffix where NNNN is a random number. - * </p> - * - * @param prefix - * prefix before the random number. - * @param suffix - * file extension; include the '.'. - * @param parentDir - * Directory to create the temporary file in; java.io.tmpdir used - * if not specified. - * - * @deprecated since ant 1.7.1 use createTempFile(String, String, File, - * boolean, boolean) instead. - * @return a File reference to the new, nonexistent temporary file. - */ - public File createTempFile(String prefix, String suffix, File parentDir) { - return createTempFile(prefix, suffix, parentDir, false, false); - } - - private static final String NULL_PLACEHOLDER = "null"; - - /** - * Create a temporary file in a given directory. - * - * <p>The file denoted by the returned abstract pathname did not - * exist before this method was invoked, any subsequent invocation - * of this method will yield a different file name.</p> - * - * @param prefix prefix before the random number. - * @param suffix file extension; include the '.'. - * @param parentDir Directory to create the temporary file in; - * java.io.tmpdir used if not specified. - * @param deleteOnExit whether to set the tempfile for deletion on - * normal VM exit. - * @param createFile true if the file must actually be created. If false - * chances exist that a file with the same name is created in the time - * between invoking this method and the moment the file is actually created. - * If possible set to true. - * - * @return a File reference to the new temporary file. - * @since Ant 1.7.1 - */ - public File createTempFile(String prefix, String suffix, File parentDir, - boolean deleteOnExit, boolean createFile) { - File result = null; - String parent = (parentDir == null) - ? System.getProperty("java.io.tmpdir") - : parentDir.getPath(); - if (prefix == null) { - prefix = NULL_PLACEHOLDER; - } - if (suffix == null) { - suffix = NULL_PLACEHOLDER; - } - - if (createFile) { - try { - result = File.createTempFile(prefix, suffix, new File(parent)); - } catch (IOException e) { - throw new BuildException("Could not create tempfile in " - + parent, e); - } - } else { - DecimalFormat fmt = new DecimalFormat("#####"); - synchronized (rand) { - do { - result = new File(parent, prefix - + fmt.format(rand.nextInt(Integer.MAX_VALUE)) + suffix); - } while (result.exists()); - } - } - - if (deleteOnExit) { - result.deleteOnExit(); - } - return result; - } - - /** - * Create a File object for a temporary file in a given directory. Without - * actually creating the file. - * - * <p> - * The file denoted by the returned abstract pathname did not exist before - * this method was invoked, any subsequent invocation of this method will - * yield a different file name. - * </p> - * <p> - * The filename is prefixNNNNNsuffix where NNNN is a random number. - * </p> - * - * @param prefix - * prefix before the random number. - * @param suffix - * file extension; include the '.'. - * @param parentDir - * Directory to create the temporary file in; java.io.tmpdir used - * if not specified. - * @param deleteOnExit - * whether to set the tempfile for deletion on normal VM exit. - * - * @deprecated since ant 1.7.1 use createTempFile(String, String, File, - * boolean, boolean) instead. - * @return a File reference to the new, nonexistent temporary file. - */ - public File createTempFile(String prefix, String suffix, - File parentDir, boolean deleteOnExit) { - return createTempFile(prefix, suffix, parentDir, deleteOnExit, false); - } - - /** - * Compares the contents of two files. - * - * @param f1 the file whose content is to be compared. - * @param f2 the other file whose content is to be compared. - * - * @return true if the content of the files is the same. - * - * @throws IOException if the files cannot be read. - */ - public boolean contentEquals(File f1, File f2) throws IOException { - return contentEquals(f1, f2, false); - } - - /** - * Compares the contents of two files. - * - * @param f1 the file whose content is to be compared. - * @param f2 the other file whose content is to be compared. - * @param textfile true if the file is to be treated as a text file and - * differences in kind of line break are to be ignored. - * - * @return true if the content of the files is the same. - * - * @throws IOException if the files cannot be read. - * @since Ant 1.6.3 - */ - public boolean contentEquals(File f1, File f2, boolean textfile) throws IOException { - return ResourceUtils.contentEquals(new FileResource(f1), new FileResource(f2), textfile); - } - - /** - * This was originally an emulation of {@link File#getParentFile} for JDK 1.1, but it is now - * implemented using that method (Ant 1.6.3 onwards). - * - * @param f the file whose parent is required. - * @return the given file's parent, or null if the file does not have a parent. - * @since 1.10 - * @deprecated since 1.7. Just use {@link File#getParentFile} directly. - */ - public File getParentFile(File f) { - return (f == null) ? null : f.getParentFile(); - } - - /** - * Read from reader till EOF. - * @param rdr the reader from which to read. - * @return the contents read out of the given reader. - * - * @throws IOException if the contents could not be read out from the - * reader. - */ - public static String readFully(Reader rdr) throws IOException { - return readFully(rdr, BUF_SIZE); - } - - /** - * Read from reader till EOF. - * - * @param rdr the reader from which to read. - * @param bufferSize the buffer size to use when reading. - * - * @return the contents read out of the given reader. - * - * @throws IOException if the contents could not be read out from the - * reader. - */ - public static String readFully(Reader rdr, int bufferSize) - throws IOException { - if (bufferSize <= 0) { - throw new IllegalArgumentException("Buffer size must be greater " - + "than 0"); - } - final char[] buffer = new char[bufferSize]; - int bufferLength = 0; - StringBuffer textBuffer = null; - while (bufferLength != -1) { - bufferLength = rdr.read(buffer); - if (bufferLength > 0) { - textBuffer = (textBuffer == null) ? new StringBuffer() : textBuffer; - textBuffer.append(new String(buffer, 0, bufferLength)); - } - } - return (textBuffer == null) ? null : textBuffer.toString(); - } - - /** - * Safe read fully - do not return a null for an empty reader. - * @param reader the input to read from. - * @return the string. - * @throws IOException if unable to read from reader. - * @since Ant 1.7.1 - */ - public static String safeReadFully(Reader reader) throws IOException { - String ret = readFully(reader); - return ret == null ? "" : ret; - } - - /** - * This was originally an emulation of File.createNewFile for JDK 1.1, - * but it is now implemented using that method (Ant 1.6.3 onwards). - * - * <p>This method has historically <strong>not</strong> guaranteed that the - * operation was atomic. In its current implementation it is. - * - * @param f the file to be created. - * @return true if the file did not exist already. - * @throws IOException on error. - * @since Ant 1.5 - */ - public boolean createNewFile(File f) throws IOException { - return f.createNewFile(); - } - - /** - * Create a new file, optionally creating parent directories. - * - * @param f the file to be created. - * @param mkdirs <code>boolean</code> whether to create parent directories. - * @return true if the file did not exist already. - * @throws IOException on error. - * @since Ant 1.6.3 - */ - public boolean createNewFile(File f, boolean mkdirs) throws IOException { - File parent = f.getParentFile(); - if (mkdirs && !(parent.exists())) { - parent.mkdirs(); - } - return f.createNewFile(); - } - - /** - * Checks whether a given file is a symbolic link. - * - * <p>It doesn't really test for symbolic links but whether the - * canonical and absolute paths of the file are identical--this - * may lead to false positives on some platforms.</p> - * - * @param parent the parent directory of the file to test - * @param name the name of the file to test. - * - * @return true if the file is a symbolic link. - * @throws IOException on error. - * @since Ant 1.5 - * @deprecated use SymbolicLinkUtils instead - */ - public boolean isSymbolicLink(File parent, String name) - throws IOException { - SymbolicLinkUtils u = SymbolicLinkUtils.getSymbolicLinkUtils(); - if (parent == null) { - return u.isSymbolicLink(name); - } - return u.isSymbolicLink(parent, name); - } - - /** - * Removes a leading path from a second path. - * - * @param leading The leading path, must not be null, must be absolute. - * @param path The path to remove from, must not be null, must be absolute. - * - * @return path's normalized absolute if it doesn't start with - * leading; path's path with leading's path removed otherwise. - * - * @since Ant 1.5 - */ - public String removeLeadingPath(File leading, File path) { - String l = normalize(leading.getAbsolutePath()).getAbsolutePath(); - String p = normalize(path.getAbsolutePath()).getAbsolutePath(); - if (l.equals(p)) { - return ""; - } - // ensure that l ends with a / - // so we never think /foo was a parent directory of /foobar - if (!l.endsWith(File.separator)) { - l += File.separator; - } - return (p.startsWith(l)) ? p.substring(l.length()) : p; - } - - /** - * Learn whether one path "leads" another. - * @param leading The leading path, must not be null, must be absolute. - * @param path The path to remove from, must not be null, must be absolute. - * @return true if path starts with leading; false otherwise. - * @since Ant 1.7 - */ - public boolean isLeadingPath(File leading, File path) { - String l = normalize(leading.getAbsolutePath()).getAbsolutePath(); - String p = normalize(path.getAbsolutePath()).getAbsolutePath(); - if (l.equals(p)) { - return true; - } - // ensure that l ends with a / - // so we never think /foo was a parent directory of /foobar - if (!l.endsWith(File.separator)) { - l += File.separator; - } - return p.startsWith(l); - } - - /** - * Constructs a <code>file:</code> URI that represents the - * external form of the given pathname. - * - * <p>Will be an absolute URI if the given path is absolute.</p> - * - * <p>This code encodes non ASCII characters too.</p> - * - * <p>The coding of the output is the same as what File.toURI().toASCIIString() produces</p> - * - * See <a href="http://www.w3.org/TR/xml11/#dt-sysid">dt-sysid</a> - * which makes some mention of how - * characters not supported by URI Reference syntax should be escaped. - * - * @param path the path in the local file system. - * @return the URI version of the local path. - * @since Ant 1.6 - */ - public String toURI(String path) { - return new File(path).toURI().toASCIIString(); - } - - /** - * Constructs a file path from a <code>file:</code> URI. - * - * <p>Will be an absolute path if the given URI is absolute.</p> - * - * <p>Swallows '%' that are not followed by two characters, - * doesn't deal with non-ASCII characters.</p> - * - * @param uri the URI designating a file in the local filesystem. - * @return the local file system path for the file. - * @since Ant 1.6 - */ - public String fromURI(String uri) { - synchronized (cacheFromUriLock) { - if (uri.equals(cacheFromUriRequest)) { - return cacheFromUriResponse; - } - String path = Locator.fromURI(uri); - String ret = isAbsolutePath(path) ? normalize(path).getAbsolutePath() : path; - cacheFromUriRequest = uri; - cacheFromUriResponse = ret; - return ret; - } - } - - /** - * Compares two filenames. - * - * <p>Unlike java.io.File#equals this method will try to compare - * the absolute paths and "normalize" the filenames - * before comparing them.</p> - * - * @param f1 the file whose name is to be compared. - * @param f2 the other file whose name is to be compared. - * - * @return true if the file are for the same file. - * - * @since Ant 1.5.3 - */ - public boolean fileNameEquals(File f1, File f2) { - return normalize(f1.getAbsolutePath()).getAbsolutePath().equals( - normalize(f2.getAbsolutePath()).getAbsolutePath()); - } - - /** - * Are the two File instances pointing to the same object on the - * file system? - * @since Ant 1.8.2 - */ - public boolean areSame(File f1, File f2) throws IOException { - if (f1 == null && f2 == null) { - return true; - } - if (f1 == null || f2 == null) { - return false; - } - File f1Normalized = normalize(f1.getAbsolutePath()); - File f2Normalized = normalize(f2.getAbsolutePath()); - return f1Normalized.equals(f2Normalized) - || f1Normalized.getCanonicalFile().equals(f2Normalized - .getCanonicalFile()); - } - - /** - * Renames a file, even if that involves crossing file system boundaries. - * - * <p>This will remove <code>to</code> (if it exists), ensure that - * <code>to</code>'s parent directory exists and move - * <code>from</code>, which involves deleting <code>from</code> as - * well.</p> - * - * @param from the file to move. - * @param to the new file name. - * - * @throws IOException if anything bad happens during this - * process. Note that <code>to</code> may have been deleted - * already when this happens. - * - * @since Ant 1.6 - */ - public void rename(File from, File to) throws IOException { - // identical logic lives in Move.renameFile(): - from = normalize(from.getAbsolutePath()).getCanonicalFile(); - to = normalize(to.getAbsolutePath()); - if (!from.exists()) { - System.err.println("Cannot rename nonexistent file " + from); - return; - } - if (from.getAbsolutePath().equals(to.getAbsolutePath())) { - System.err.println("Rename of " + from + " to " + to + " is a no-op."); - return; - } - if (to.exists() && !(areSame(from, to) || tryHardToDelete(to))) { - throw new IOException("Failed to delete " + to + " while trying to rename " + from); - } - File parent = to.getParentFile(); - if (parent != null && !parent.isDirectory() - && !(parent.mkdirs() || parent.isDirectory())) { - throw new IOException("Failed to create directory " + parent - + " while trying to rename " + from); - } - if (!from.renameTo(to)) { - copyFile(from, to); - if (!tryHardToDelete(from)) { - throw new IOException("Failed to delete " + from + " while trying to rename it."); - } - } - } - - /** - * Get the granularity of file timestamps. The choice is made based on OS, which is - * incorrect--it should really be by filesystem. We do not have an easy way to probe for file - * systems, however, so this heuristic gives us a decent default. - * - * @return the difference, in milliseconds, which two file timestamps must have in order for the - * two files to be considered to have different timestamps. - */ - public long getFileTimestampGranularity() { - if (ON_WIN9X) { - return FAT_FILE_TIMESTAMP_GRANULARITY; - } - if (ON_WINDOWS) { - return NTFS_FILE_TIMESTAMP_GRANULARITY; - } - if (ON_DOS) { - return FAT_FILE_TIMESTAMP_GRANULARITY; - } - return UNIX_FILE_TIMESTAMP_GRANULARITY; - } - - /** - * test whether a file or directory exists, with an error in the - * upper/lower case spelling of the name. - * Using this method is only interesting on case insensitive file systems - * (Windows).<br> - * It will return true only if 3 conditions are met : - * <br> - * <ul> - * <li>operating system is case insensitive</li> - * <li>file exists</li> - * <li>actual name from directory reading is different from the - * supplied argument</li> - * </ul> - * <br> - * the purpose is to identify files or directories on case-insensitive - * filesystems whose case is not what is expected.<br> - * Possibly to rename them afterwards to the desired upper/lowercase - * combination. - * - * @param localFile file to test - * @return true if the file exists and the case of the actual file - * is not the case of the parameter - * @since Ant 1.7.1 - */ - public boolean hasErrorInCase(File localFile) { - localFile = normalize(localFile.getAbsolutePath()); - if (!localFile.exists()) { - return false; - } - final String localFileName = localFile.getName(); - FilenameFilter ff = new FilenameFilter () { - public boolean accept(File dir, String name) { - return name.equalsIgnoreCase(localFileName) && (!name.equals(localFileName)); - } - }; - String[] names = localFile.getParentFile().list(ff); - return names != null && names.length == 1; - } - - /** - * Returns true if the source is older than the dest. - * If the dest file does not exist, then the test returns false; it is - * implicitly not up do date. - * @param source source file (should be the older). - * @param dest dest file (should be the newer). - * @param granularity an offset added to the source time. - * @return true if the source is older than the dest after accounting - * for granularity. - * @since Ant 1.6.3 - */ - public boolean isUpToDate(File source, File dest, long granularity) { - //do a check for the destination file existing - if (!dest.exists()) { - //if it does not, then the file is not up to date. - return false; - } - long sourceTime = source.lastModified(); - long destTime = dest.lastModified(); - return isUpToDate(sourceTime, destTime, granularity); - } - - /** - * Returns true if the source is older than the dest. - * @param source source file (should be the older). - * @param dest dest file (should be the newer). - * @return true if the source is older than the dest, taking the granularity into account. - * @since Ant 1.6.3 - */ - public boolean isUpToDate(File source, File dest) { - return isUpToDate(source, dest, getFileTimestampGranularity()); - } - - /** - * Compare two timestamps for being up to date using - * the specified granularity. - * - * @param sourceTime timestamp of source file. - * @param destTime timestamp of dest file. - * @param granularity os/filesys granularity. - * @return true if the dest file is considered up to date. - */ - public boolean isUpToDate(long sourceTime, long destTime, long granularity) { - return destTime != -1 && destTime >= sourceTime + granularity; - } - - /** - * Compare two timestamps for being up to date using the - * current granularity. - * - * @param sourceTime timestamp of source file. - * @param destTime timestamp of dest file. - * @return true if the dest file is considered up to date. - */ - public boolean isUpToDate(long sourceTime, long destTime) { - return isUpToDate(sourceTime, destTime, getFileTimestampGranularity()); - } - - /** - * Close a Writer without throwing any exception if something went wrong. - * Do not attempt to close it if the argument is null. - * @param device output writer, can be null. - */ - public static void close(Writer device) { - if (null != device) { - try { - device.close(); - } catch (IOException e) { - //ignore - } - } - } - - /** - * Close a Reader without throwing any exception if something went wrong. - * Do not attempt to close it if the argument is null. - * - * @param device Reader, can be null. - */ - public static void close(Reader device) { - if (null != device) { - try { - device.close(); - } catch (IOException e) { - //ignore - } - } - } - - /** - * Close a stream without throwing any exception if something went wrong. - * Do not attempt to close it if the argument is null. - * - * @param device stream, can be null. - */ - public static void close(OutputStream device) { - if (null != device) { - try { - device.close(); - } catch (IOException e) { - //ignore - } - } - } - - /** - * Close a stream without throwing any exception if something went wrong. - * Do not attempt to close it if the argument is null. - * - * @param device stream, can be null. - */ - public static void close(InputStream device) { - if (null != device) { - try { - device.close(); - } catch (IOException e) { - //ignore - } - } - } - - /** - * Close a Channel without throwing any exception if something went wrong. - * Do not attempt to close it if the argument is null. - * - * @param device channel, can be null. - * @since Ant 1.8.0 - */ - public static void close(Channel device) { - if (null != device) { - try { - device.close(); - } catch (IOException e) { - //ignore - } - } - } - - /** - * Closes an URLConnection if its concrete implementation provides - * a way to close it that Ant knows of. - * - * @param conn connection, can be null - * @since Ant 1.8.0 - */ - public static void close(URLConnection conn) { - if (conn != null) { - try { - if (conn instanceof JarURLConnection) { - JarURLConnection juc = (JarURLConnection) conn; - JarFile jf = juc.getJarFile(); - jf.close(); - jf = null; - } else if (conn instanceof HttpURLConnection) { - ((HttpURLConnection) conn).disconnect(); - } - } catch (IOException exc) { - //ignore - } - } - } - - /** - * Delete the file with {@link File#delete()} if the argument is not null. - * Do nothing on a null argument. - * @param file file to delete. - */ - public static void delete(File file) { - if (file != null) { - file.delete(); - } - } - - /** - * Accommodate Windows bug encountered in both Sun and IBM JDKs. - * Others possible. If the delete does not work, call System.gc(), - * wait a little and try again. - * - * @return whether deletion was successful - * @since Ant 1.8.0 - */ - public boolean tryHardToDelete(File f) { - return tryHardToDelete(f, ON_WINDOWS); - } - - /** - * If delete does not work, call System.gc() if asked to, wait a - * little and try again. - * - * @return whether deletion was successful - * @since Ant 1.8.3 - */ - public boolean tryHardToDelete(File f, boolean runGC) { - if (!f.delete()) { - if (runGC) { - System.gc(); - } - try { - Thread.sleep(DELETE_RETRY_SLEEP_MILLIS); - } catch (InterruptedException ex) { - // Ignore Exception - } - return f.delete(); - } - return true; - } - - /** - * Calculates the relative path between two files. - * <p> - * Implementation note:<br>This function may throw an IOException if an I/O error occurs - * because its use of the canonical pathname may require filesystem queries. - * </p> - * - * @param fromFile the <code>File</code> to calculate the path from - * @param toFile the <code>File</code> to calculate the path to - * @return the relative path between the files - * @throws Exception for undocumented reasons - * @see File#getCanonicalPath() - * - * @since Ant 1.7 - */ - public static String getRelativePath(File fromFile, File toFile) throws Exception { - String fromPath = fromFile.getCanonicalPath(); - String toPath = toFile.getCanonicalPath(); - - // build the path stack info to compare - String[] fromPathStack = getPathStack(fromPath); - String[] toPathStack = getPathStack(toPath); - - if (0 < toPathStack.length && 0 < fromPathStack.length) { - if (!fromPathStack[0].equals(toPathStack[0])) { - // not the same device (would be "" on Linux/Unix) - - return getPath(Arrays.asList(toPathStack)); - } - } else { - // no comparison possible - return getPath(Arrays.asList(toPathStack)); - } - - int minLength = Math.min(fromPathStack.length, toPathStack.length); - int same = 1; // Used outside the for loop - - // get index of parts which are equal - for (; - same < minLength && fromPathStack[same].equals(toPathStack[same]); - same++) { - // Do nothing - } - - List relativePathStack = new ArrayList(); - - // if "from" part is longer, fill it up with ".." - // to reach path which is equal to both paths - for (int i = same; i < fromPathStack.length; i++) { - relativePathStack.add(".."); - } - - // fill it up path with parts which were not equal - for (int i = same; i < toPathStack.length; i++) { - relativePathStack.add(toPathStack[i]); - } - - return getPath(relativePathStack); - } - - /** - * Gets all names of the path as an array of <code>String</code>s. - * - * @param path to get names from - * @return <code>String</code>s, never <code>null</code> - * - * @since Ant 1.7 - */ - public static String[] getPathStack(String path) { - String normalizedPath = path.replace(File.separatorChar, '/'); - - return normalizedPath.split("/"); - } - - /** - * Gets path from a <code>List</code> of <code>String</code>s. - * - * @param pathStack <code>List</code> of <code>String</code>s to be concatenated as a path. - * @return <code>String</code>, never <code>null</code> - * - * @since Ant 1.7 - */ - public static String getPath(List pathStack) { - // can safely use '/' because Windows understands '/' as separator - return getPath(pathStack, '/'); - } - - /** - * Gets path from a <code>List</code> of <code>String</code>s. - * - * @param pathStack <code>List</code> of <code>String</code>s to be concated as a path. - * @param separatorChar <code>char</code> to be used as separator between names in path - * @return <code>String</code>, never <code>null</code> - * - * @since Ant 1.7 - */ - public static String getPath(final List pathStack, final char separatorChar) { - final StringBuffer buffer = new StringBuffer(); - - final Iterator iter = pathStack.iterator(); - if (iter.hasNext()) { - buffer.append(iter.next()); - } - while (iter.hasNext()) { - buffer.append(separatorChar); - buffer.append(iter.next()); - } - return buffer.toString(); - } - - /** - * Get the default encoding. - * This is done by opening an InputStreamReader on - * a dummy InputStream and getting the encoding. - * Could use System.getProperty("file.encoding"), but cannot - * see where this is documented. - * @return the default file encoding. - */ - public String getDefaultEncoding() { - InputStreamReader is = new InputStreamReader( - new InputStream() { - public int read() { - return -1; - } - }); - try { - return is.getEncoding(); - } finally { - close(is); - } - } -} |