diff --git a/Dorkbox-Util/LICENSE.TXT b/Dorkbox-Util/LICENSE.TXT index 3e33be0..73bc147 100644 --- a/Dorkbox-Util/LICENSE.TXT +++ b/Dorkbox-Util/LICENSE.TXT @@ -94,7 +94,7 @@ Legal: - - FilenameUtils.java, IOCase.java - Apache 2.0 License + - FilenameUtils.java (normalize + dependencies) - Apache 2.0 License http://commons.apache.org/proper/commons-io/ Copyright 2013 ASF Authors: Kevin A. Burton, Scott Sanders, Daniel Rall, Christoph.Reck, diff --git a/Dorkbox-Util/src/dorkbox/util/FileUtil.java b/Dorkbox-Util/src/dorkbox/util/FileUtil.java index 0c37d8f..65b7f7d 100644 --- a/Dorkbox-Util/src/dorkbox/util/FileUtil.java +++ b/Dorkbox-Util/src/dorkbox/util/FileUtil.java @@ -23,9 +23,44 @@ import org.slf4j.LoggerFactory; /** * File related utilities. + * + * + * Contains code from FilenameUtils.java (normalize + dependencies) - Apache 2.0 License + * http://commons.apache.org/proper/commons-io/ + * Copyright 2013 ASF + * Authors: Kevin A. Burton, Scott Sanders, Daniel Rall, Christoph.Reck, + * Peter Donald, Jeff Turner, Matthew Hawthorne, Martin Cooper, + * Jeremias Maerki, Stephen Colebourne */ public class FileUtil { private static final Logger logger = LoggerFactory.getLogger(FileUtil.class); + /** + * The Unix separator character. + */ + private static final char UNIX_SEPARATOR = '/'; + + /** + * The Windows separator character. + */ + private static final char WINDOWS_SEPARATOR = '\\'; + + /** + * The system separator character. + */ + private static final char SYSTEM_SEPARATOR = File.separatorChar; + + /** + * The separator character that is the opposite of the system separator. + */ + private static final char OTHER_SEPARATOR; + static { + if (OS.isWindows()) { + OTHER_SEPARATOR = UNIX_SEPARATOR; + } else { + OTHER_SEPARATOR = WINDOWS_SEPARATOR; + } + } + public static byte[] ZIP_HEADER = { 'P', 'K', 0x3, 0x4 }; @@ -118,8 +153,8 @@ public class FileUtil { } - String normalizedIn = FilenameUtils.normalize(in.getAbsolutePath()); - String normalizedout = FilenameUtils.normalize(out.getAbsolutePath()); + String normalizedIn = normalize(in.getAbsolutePath()); + String normalizedout = normalize(out.getAbsolutePath()); // if out doesn't exist, then create it. File parentOut = out.getParentFile(); @@ -162,7 +197,7 @@ public class FileUtil { * Copies the contents of file two onto the END of file one. */ @SuppressWarnings("resource") - public static File concatFiles(File one, File two) throws IOException { + public static File concatFiles(File one, File two) { if (one == null) { throw new IllegalArgumentException("one cannot be null."); } @@ -170,8 +205,8 @@ public class FileUtil { throw new IllegalArgumentException("two cannot be null."); } - String normalizedOne = FilenameUtils.normalize(one.getAbsolutePath()); - String normalizedTwo = FilenameUtils.normalize(two.getAbsolutePath()); + String normalizedOne = normalize(one.getAbsolutePath()); + String normalizedTwo = normalize(two.getAbsolutePath()); Logger logger2 = logger; if (logger2.isTraceEnabled()) { @@ -215,7 +250,7 @@ public class FileUtil { /** * Moves a file, overwriting any existing file at the destination. */ - public static File moveFile(String in, String out) throws IOException { + public static File moveFile(String in, String out) { if (in == null || in.isEmpty()) { throw new IllegalArgumentException("in cannot be null."); } @@ -229,7 +264,7 @@ public class FileUtil { /** * Moves a file, overwriting any existing file at the destination. */ - public static File moveFile(File in, File out) throws IOException { + public static File moveFile(File in, File out) { if (in == null) { throw new IllegalArgumentException("in cannot be null."); } @@ -918,4 +953,447 @@ public class FileUtil { return null; } + + + //----------------------------------------------------------------------- + /** + * Normalizes a path, removing double and single dot path steps. + *
+ * This method normalizes a path to a standard format. + * The input may contain separators in either Unix or Windows format. + * The output will contain separators in the format of the system. + *
+ * A trailing slash will be retained. + * A double slash will be merged to a single slash (but UNC names are handled). + * A single dot path segment will be removed. + * A double dot will cause that path segment and the one before to be removed. + * If the double dot has no parent path segment to work with, {@code null} + * is returned. + *
+ * The output will be the same on both Unix and Windows except + * for the separator character. + *
+ * /foo// --> /foo/ + * /foo/./ --> /foo/ + * /foo/../bar --> /bar + * /foo/../bar/ --> /bar/ + * /foo/../bar/../baz --> /baz + * //foo//./bar --> /foo/bar + * /../ --> null + * ../foo --> null + * foo/bar/.. --> foo/ + * foo/../../bar --> null + * foo/../bar --> bar + * //server/foo/../bar --> //server/bar + * //server/../bar --> null + * C:\foo\..\bar --> C:\bar + * C:\..\bar --> null + * ~/foo/../bar/ --> ~/bar/ + * ~/../bar --> null + *+ * (Note the file separator returned will be correct for Windows/Unix) + * + * @param filename the filename to normalize, null returns null + * @return the normalized filename, or null if invalid + */ + public static String normalize(String filename) { + return doNormalize(filename, SYSTEM_SEPARATOR, true); + } + + /** + * Normalizes a path, removing double and single dot path steps. + *
+ * This method normalizes a path to a standard format. + * The input may contain separators in either Unix or Windows format. + * The output will contain separators in the format of the system. + *
+ * A trailing slash will be retained. + * A double slash will be merged to a single slash (but UNC names are handled). + * A single dot path segment will be removed. + * A double dot will cause that path segment and the one before to be removed. + * If the double dot has no parent path segment to work with, {@code null} + * is returned. + *
+ * The output will be the same on both Unix and Windows except + * for the separator character. + *
+ * /foo// --> /foo/ + * /foo/./ --> /foo/ + * /foo/../bar --> /bar + * /foo/../bar/ --> /bar/ + * /foo/../bar/../baz --> /baz + * //foo//./bar --> /foo/bar + * /../ --> null + * ../foo --> null + * foo/bar/.. --> foo/ + * foo/../../bar --> null + * foo/../bar --> bar + * //server/foo/../bar --> //server/bar + * //server/../bar --> null + * C:\foo\..\bar --> C:\bar + * C:\..\bar --> null + * ~/foo/../bar/ --> ~/bar/ + * ~/../bar --> null + *+ * (Note the file separator returned will be correct for Windows/Unix) + * + * @param file the file to normalize, null returns null + * @return the normalized file, or null if invalid + */ + public static File normalize(File file) { + if (file == null) { + return null; + } + + String asString = doNormalize(file.getAbsolutePath(), SYSTEM_SEPARATOR, true); + if (asString == null) { + return null; + } + + return new File(asString); + } + + + /** + * Normalizes a path, removing double and single dot path steps. + *
+ * This method normalizes a path to a standard format. + * The input may contain separators in either Unix or Windows format. + * The output will contain separators in the format specified. + *
+ * A trailing slash will be retained. + * A double slash will be merged to a single slash (but UNC names are handled). + * A single dot path segment will be removed. + * A double dot will cause that path segment and the one before to be removed. + * If the double dot has no parent path segment to work with, {@code null} + * is returned. + *
+ * The output will be the same on both Unix and Windows except + * for the separator character. + *
+ * /foo// --> /foo/ + * /foo/./ --> /foo/ + * /foo/../bar --> /bar + * /foo/../bar/ --> /bar/ + * /foo/../bar/../baz --> /baz + * //foo//./bar --> /foo/bar + * /../ --> null + * ../foo --> null + * foo/bar/.. --> foo/ + * foo/../../bar --> null + * foo/../bar --> bar + * //server/foo/../bar --> //server/bar + * //server/../bar --> null + * C:\foo\..\bar --> C:\bar + * C:\..\bar --> null + * ~/foo/../bar/ --> ~/bar/ + * ~/../bar --> null + *+ * The output will be the same on both Unix and Windows including + * the separator character. + * + * @param filename the filename to normalize, null returns null + * @param unixSeparator {@code true} if a unix separator should + * be used or {@code false} if a windows separator should be used. + * @return the normalized filename, or null if invalid + * @since 2.0 + */ + public static String normalize(String filename, boolean unixSeparator) { + char separator = unixSeparator ? UNIX_SEPARATOR : WINDOWS_SEPARATOR; + return doNormalize(filename, separator, true); + } + + //----------------------------------------------------------------------- + /** + * Normalizes a path, removing double and single dot path steps, + * and removing any final directory separator. + *
+ * This method normalizes a path to a standard format. + * The input may contain separators in either Unix or Windows format. + * The output will contain separators in the format of the system. + *
+ * A trailing slash will be removed. + * A double slash will be merged to a single slash (but UNC names are handled). + * A single dot path segment will be removed. + * A double dot will cause that path segment and the one before to be removed. + * If the double dot has no parent path segment to work with, {@code null} + * is returned. + *
+ * The output will be the same on both Unix and Windows except + * for the separator character. + *
+ * /foo// --> /foo + * /foo/./ --> /foo + * /foo/../bar --> /bar + * /foo/../bar/ --> /bar + * /foo/../bar/../baz --> /baz + * //foo//./bar --> /foo/bar + * /../ --> null + * ../foo --> null + * foo/bar/.. --> foo + * foo/../../bar --> null + * foo/../bar --> bar + * //server/foo/../bar --> //server/bar + * //server/../bar --> null + * C:\foo\..\bar --> C:\bar + * C:\..\bar --> null + * ~/foo/../bar/ --> ~/bar + * ~/../bar --> null + *+ * (Note the file separator returned will be correct for Windows/Unix) + * + * @param filename the filename to normalize, null returns null + * @return the normalized filename, or null if invalid + */ + public static String normalizeNoEndSeparator(String filename) { + return doNormalize(filename, SYSTEM_SEPARATOR, false); + } + + /** + * Normalizes a path, removing double and single dot path steps, + * and removing any final directory separator. + *
+ * This method normalizes a path to a standard format. + * The input may contain separators in either Unix or Windows format. + * The output will contain separators in the format specified. + *
+ * A trailing slash will be removed. + * A double slash will be merged to a single slash (but UNC names are handled). + * A single dot path segment will be removed. + * A double dot will cause that path segment and the one before to be removed. + * If the double dot has no parent path segment to work with, {@code null} + * is returned. + *
+ * The output will be the same on both Unix and Windows including + * the separator character. + *
+ * /foo// --> /foo + * /foo/./ --> /foo + * /foo/../bar --> /bar + * /foo/../bar/ --> /bar + * /foo/../bar/../baz --> /baz + * //foo//./bar --> /foo/bar + * /../ --> null + * ../foo --> null + * foo/bar/.. --> foo + * foo/../../bar --> null + * foo/../bar --> bar + * //server/foo/../bar --> //server/bar + * //server/../bar --> null + * C:\foo\..\bar --> C:\bar + * C:\..\bar --> null + * ~/foo/../bar/ --> ~/bar + * ~/../bar --> null + *+ * + * @param filename the filename to normalize, null returns null + * @param unixSeparator {@code true} if a unix separator should + * be used or {@code false} if a windows separtor should be used. + * @return the normalized filename, or null if invalid + * @since 2.0 + */ + public static String normalizeNoEndSeparator(String filename, boolean unixSeparator) { + char separator = unixSeparator ? UNIX_SEPARATOR : WINDOWS_SEPARATOR; + return doNormalize(filename, separator, false); + } + + /** + * Internal method to perform the normalization. + * + * @param filename the filename + * @param separator The separator character to use + * @param keepSeparator true to keep the final separator + * @return the normalized filename + */ + private static String doNormalize(String filename, char separator, boolean keepSeparator) { + if (filename == null) { + return null; + } + int size = filename.length(); + if (size == 0) { + return filename; + } + int prefix = getPrefixLength(filename); + if (prefix < 0) { + return null; + } + + char[] array = new char[size + 2]; // +1 for possible extra slash, +2 for arraycopy + filename.getChars(0, filename.length(), array, 0); + + // fix separators throughout + char otherSeparator = separator == SYSTEM_SEPARATOR ? OTHER_SEPARATOR : SYSTEM_SEPARATOR; + for (int i = 0; i < array.length; i++) { + if (array[i] == otherSeparator) { + array[i] = separator; + } + } + + // add extra separator on the end to simplify code below + boolean lastIsDirectory = true; + if (array[size - 1] != separator) { + array[size++] = separator; + lastIsDirectory = false; + } + + // adjoining slashes + for (int i = prefix + 1; i < size; i++) { + if (array[i] == separator && array[i - 1] == separator) { + System.arraycopy(array, i, array, i - 1, size - i); + size--; + i--; + } + } + + // dot slash + for (int i = prefix + 1; i < size; i++) { + if (array[i] == separator && array[i - 1] == '.' && + (i == prefix + 1 || array[i - 2] == separator)) { + if (i == size - 1) { + lastIsDirectory = true; + } + System.arraycopy(array, i + 1, array, i - 1, size - i); + size -=2; + i--; + } + } + + // double dot slash + outer: + for (int i = prefix + 2; i < size; i++) { + if (array[i] == separator && array[i - 1] == '.' && array[i - 2] == '.' && + (i == prefix + 2 || array[i - 3] == separator)) { + if (i == prefix + 2) { + return null; + } + if (i == size - 1) { + lastIsDirectory = true; + } + int j; + for (j = i - 4 ; j >= prefix; j--) { + if (array[j] == separator) { + // remove b/../ from a/b/../c + System.arraycopy(array, i + 1, array, j + 1, size - i); + size -= i - j; + i = j + 1; + continue outer; + } + } + // remove a/../ from a/../c + System.arraycopy(array, i + 1, array, prefix, size - i); + size -= i + 1 - prefix; + i = prefix + 1; + } + } + + if (size <= 0) { // should never be less than 0 + return ""; + } + if (size <= prefix) { // should never be less than prefix + return new String(array, 0, size); + } + if (lastIsDirectory && keepSeparator) { + return new String(array, 0, size); // keep trailing separator + } + return new String(array, 0, size - 1); // lose trailing separator + } + + //----------------------------------------------------------------------- + /** + * Returns the length of the filename prefix, such as
C:/
or ~/
.
+ * + * This method will handle a file in either Unix or Windows format. + *
+ * The prefix length includes the first slash in the full filename + * if applicable. Thus, it is possible that the length returned is greater + * than the length of the input string. + *
+ * Windows: + * a\b\c.txt --> "" --> relative + * \a\b\c.txt --> "\" --> current drive absolute + * C:a\b\c.txt --> "C:" --> drive relative + * C:\a\b\c.txt --> "C:\" --> absolute + * \\server\a\b\c.txt --> "\\server\" --> UNC + * + * Unix: + * a/b/c.txt --> "" --> relative + * /a/b/c.txt --> "/" --> absolute + * ~/a/b/c.txt --> "~/" --> current user + * ~ --> "~/" --> current user (slash added) + * ~user/a/b/c.txt --> "~user/" --> named user + * ~user --> "~user/" --> named user (slash added) + *+ *
+ * The output will be the same irrespective of the machine that the code is running on. + * ie. both Unix and Windows prefixes are matched regardless. + * + * @param filename the filename to find the prefix in, null returns -1 + * @return the length of the prefix, -1 if invalid or null + */ + public static int getPrefixLength(String filename) { + if (filename == null) { + return -1; + } + int len = filename.length(); + if (len == 0) { + return 0; + } + char ch0 = filename.charAt(0); + if (ch0 == ':') { + return -1; + } + if (len == 1) { + if (ch0 == '~') { + return 2; // return a length greater than the input + } + return isSeparator(ch0) ? 1 : 0; + } else { + if (ch0 == '~') { + int posUnix = filename.indexOf(UNIX_SEPARATOR, 1); + int posWin = filename.indexOf(WINDOWS_SEPARATOR, 1); + if (posUnix == -1 && posWin == -1) { + return len + 1; // return a length greater than the input + } + posUnix = posUnix == -1 ? posWin : posUnix; + posWin = posWin == -1 ? posUnix : posWin; + return Math.min(posUnix, posWin) + 1; + } + char ch1 = filename.charAt(1); + if (ch1 == ':') { + ch0 = Character.toUpperCase(ch0); + if (ch0 >= 'A' && ch0 <= 'Z') { + if (len == 2 || isSeparator(filename.charAt(2)) == false) { + return 2; + } + return 3; + } + return -1; + + } else if (isSeparator(ch0) && isSeparator(ch1)) { + int posUnix = filename.indexOf(UNIX_SEPARATOR, 2); + int posWin = filename.indexOf(WINDOWS_SEPARATOR, 2); + if (posUnix == -1 && posWin == -1 || posUnix == 2 || posWin == 2) { + return -1; + } + posUnix = posUnix == -1 ? posWin : posUnix; + posWin = posWin == -1 ? posUnix : posWin; + return Math.min(posUnix, posWin) + 1; + } else { + return isSeparator(ch0) ? 1 : 0; + } + } + } + + //----------------------------------------------------------------------- + /** + * Checks if the character is a separator. + * + * @param ch the character to check + * @return true if it is a separator character + */ + private static boolean isSeparator(char ch) { + return ch == UNIX_SEPARATOR || ch == WINDOWS_SEPARATOR; + } + + } diff --git a/Dorkbox-Util/src/dorkbox/util/FilenameUtils.java b/Dorkbox-Util/src/dorkbox/util/FilenameUtils.java deleted file mode 100644 index ff2a2a7..0000000 --- a/Dorkbox-Util/src/dorkbox/util/FilenameUtils.java +++ /dev/null @@ -1,1401 +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 dorkbox.util; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Stack; - -/** - * General filename and filepath manipulation utilities. - *
- * When dealing with filenames you can hit problems when moving from a Windows - * based development machine to a Unix based production machine. - * This class aims to help avoid those problems. - *
- * NOTE: You may be able to avoid using this class entirely simply by - * using JDK {@link java.io.File File} objects and the two argument constructor - * {@link java.io.File#File(java.io.File, java.lang.String) File(File,String)}. - *
- * Most methods on this class are designed to work the same on both Unix and Windows. - * Those that don't include 'System', 'Unix' or 'Windows' in their name. - *
- * Most methods recognise both separators (forward and back), and both - * sets of prefixes. See the javadoc of each method for details. - *
- * This class defines six components within a filename - * (example C:\dev\project\file.txt): - *
- * This class only supports Unix and Windows style names. - * Prefixes are matched as follows: - *
- * Windows: - * a\b\c.txt --> "" --> relative - * \a\b\c.txt --> "\" --> current drive absolute - * C:a\b\c.txt --> "C:" --> drive relative - * C:\a\b\c.txt --> "C:\" --> absolute - * \\server\a\b\c.txt --> "\\server\" --> UNC - * - * Unix: - * a/b/c.txt --> "" --> relative - * /a/b/c.txt --> "/" --> absolute - * ~/a/b/c.txt --> "~/" --> current user - * ~ --> "~/" --> current user (slash added) - * ~user/a/b/c.txt --> "~user/" --> named user - * ~user --> "~user/" --> named user (slash added) - *- * Both prefix styles are matched always, irrespective of the machine that you are - * currently running on. - *
- * Origin of code: Excalibur, Alexandria, Tomcat, Commons-Utils. - * - * @version $Id: FilenameUtils.java 1307462 2012-03-30 15:13:11Z ggregory $ - * @since 1.1 - */ -public class FilenameUtils { - - /** - * The extension separator character. - * @since 1.4 - */ - public static final char EXTENSION_SEPARATOR = '.'; - - /** - * The extension separator String. - * @since 1.4 - */ - public static final String EXTENSION_SEPARATOR_STR = Character.toString(EXTENSION_SEPARATOR); - - /** - * The Unix separator character. - */ - private static final char UNIX_SEPARATOR = '/'; - - /** - * The Windows separator character. - */ - private static final char WINDOWS_SEPARATOR = '\\'; - - /** - * The system separator character. - */ - private static final char SYSTEM_SEPARATOR = File.separatorChar; - - /** - * The separator character that is the opposite of the system separator. - */ - private static final char OTHER_SEPARATOR; - static { - if (isSystemWindows()) { - OTHER_SEPARATOR = UNIX_SEPARATOR; - } else { - OTHER_SEPARATOR = WINDOWS_SEPARATOR; - } - } - - /** - * Instances should NOT be constructed in standard programming. - */ - public FilenameUtils() { - super(); - } - - //----------------------------------------------------------------------- - /** - * Determines if Windows file system is in use. - * - * @return true if the system is Windows - */ - static boolean isSystemWindows() { - return SYSTEM_SEPARATOR == WINDOWS_SEPARATOR; - } - - //----------------------------------------------------------------------- - /** - * Checks if the character is a separator. - * - * @param ch the character to check - * @return true if it is a separator character - */ - private static boolean isSeparator(char ch) { - return ch == UNIX_SEPARATOR || ch == WINDOWS_SEPARATOR; - } - - //----------------------------------------------------------------------- - /** - * Normalizes a path, removing double and single dot path steps. - *
- * This method normalizes a path to a standard format. - * The input may contain separators in either Unix or Windows format. - * The output will contain separators in the format of the system. - *
- * A trailing slash will be retained. - * A double slash will be merged to a single slash (but UNC names are handled). - * A single dot path segment will be removed. - * A double dot will cause that path segment and the one before to be removed. - * If the double dot has no parent path segment to work with, {@code null} - * is returned. - *
- * The output will be the same on both Unix and Windows except - * for the separator character. - *
- * /foo// --> /foo/ - * /foo/./ --> /foo/ - * /foo/../bar --> /bar - * /foo/../bar/ --> /bar/ - * /foo/../bar/../baz --> /baz - * //foo//./bar --> /foo/bar - * /../ --> null - * ../foo --> null - * foo/bar/.. --> foo/ - * foo/../../bar --> null - * foo/../bar --> bar - * //server/foo/../bar --> //server/bar - * //server/../bar --> null - * C:\foo\..\bar --> C:\bar - * C:\..\bar --> null - * ~/foo/../bar/ --> ~/bar/ - * ~/../bar --> null - *- * (Note the file separator returned will be correct for Windows/Unix) - * - * @param filename the filename to normalize, null returns null - * @return the normalized filename, or null if invalid - */ - public static String normalize(String filename) { - return doNormalize(filename, SYSTEM_SEPARATOR, true); - } - /** - * Normalizes a path, removing double and single dot path steps. - *
- * This method normalizes a path to a standard format. - * The input may contain separators in either Unix or Windows format. - * The output will contain separators in the format specified. - *
- * A trailing slash will be retained. - * A double slash will be merged to a single slash (but UNC names are handled). - * A single dot path segment will be removed. - * A double dot will cause that path segment and the one before to be removed. - * If the double dot has no parent path segment to work with, {@code null} - * is returned. - *
- * The output will be the same on both Unix and Windows except - * for the separator character. - *
- * /foo// --> /foo/ - * /foo/./ --> /foo/ - * /foo/../bar --> /bar - * /foo/../bar/ --> /bar/ - * /foo/../bar/../baz --> /baz - * //foo//./bar --> /foo/bar - * /../ --> null - * ../foo --> null - * foo/bar/.. --> foo/ - * foo/../../bar --> null - * foo/../bar --> bar - * //server/foo/../bar --> //server/bar - * //server/../bar --> null - * C:\foo\..\bar --> C:\bar - * C:\..\bar --> null - * ~/foo/../bar/ --> ~/bar/ - * ~/../bar --> null - *- * The output will be the same on both Unix and Windows including - * the separator character. - * - * @param filename the filename to normalize, null returns null - * @param unixSeparator {@code true} if a unix separator should - * be used or {@code false} if a windows separator should be used. - * @return the normalized filename, or null if invalid - * @since 2.0 - */ - public static String normalize(String filename, boolean unixSeparator) { - char separator = unixSeparator ? UNIX_SEPARATOR : WINDOWS_SEPARATOR; - return doNormalize(filename, separator, true); - } - - //----------------------------------------------------------------------- - /** - * Normalizes a path, removing double and single dot path steps, - * and removing any final directory separator. - *
- * This method normalizes a path to a standard format. - * The input may contain separators in either Unix or Windows format. - * The output will contain separators in the format of the system. - *
- * A trailing slash will be removed. - * A double slash will be merged to a single slash (but UNC names are handled). - * A single dot path segment will be removed. - * A double dot will cause that path segment and the one before to be removed. - * If the double dot has no parent path segment to work with, {@code null} - * is returned. - *
- * The output will be the same on both Unix and Windows except - * for the separator character. - *
- * /foo// --> /foo - * /foo/./ --> /foo - * /foo/../bar --> /bar - * /foo/../bar/ --> /bar - * /foo/../bar/../baz --> /baz - * //foo//./bar --> /foo/bar - * /../ --> null - * ../foo --> null - * foo/bar/.. --> foo - * foo/../../bar --> null - * foo/../bar --> bar - * //server/foo/../bar --> //server/bar - * //server/../bar --> null - * C:\foo\..\bar --> C:\bar - * C:\..\bar --> null - * ~/foo/../bar/ --> ~/bar - * ~/../bar --> null - *- * (Note the file separator returned will be correct for Windows/Unix) - * - * @param filename the filename to normalize, null returns null - * @return the normalized filename, or null if invalid - */ - public static String normalizeNoEndSeparator(String filename) { - return doNormalize(filename, SYSTEM_SEPARATOR, false); - } - - /** - * Normalizes a path, removing double and single dot path steps, - * and removing any final directory separator. - *
- * This method normalizes a path to a standard format. - * The input may contain separators in either Unix or Windows format. - * The output will contain separators in the format specified. - *
- * A trailing slash will be removed. - * A double slash will be merged to a single slash (but UNC names are handled). - * A single dot path segment will be removed. - * A double dot will cause that path segment and the one before to be removed. - * If the double dot has no parent path segment to work with, {@code null} - * is returned. - *
- * The output will be the same on both Unix and Windows including - * the separator character. - *
- * /foo// --> /foo - * /foo/./ --> /foo - * /foo/../bar --> /bar - * /foo/../bar/ --> /bar - * /foo/../bar/../baz --> /baz - * //foo//./bar --> /foo/bar - * /../ --> null - * ../foo --> null - * foo/bar/.. --> foo - * foo/../../bar --> null - * foo/../bar --> bar - * //server/foo/../bar --> //server/bar - * //server/../bar --> null - * C:\foo\..\bar --> C:\bar - * C:\..\bar --> null - * ~/foo/../bar/ --> ~/bar - * ~/../bar --> null - *- * - * @param filename the filename to normalize, null returns null - * @param unixSeparator {@code true} if a unix separator should - * be used or {@code false} if a windows separtor should be used. - * @return the normalized filename, or null if invalid - * @since 2.0 - */ - public static String normalizeNoEndSeparator(String filename, boolean unixSeparator) { - char separator = unixSeparator ? UNIX_SEPARATOR : WINDOWS_SEPARATOR; - return doNormalize(filename, separator, false); - } - - /** - * Internal method to perform the normalization. - * - * @param filename the filename - * @param separator The separator character to use - * @param keepSeparator true to keep the final separator - * @return the normalized filename - */ - private static String doNormalize(String filename, char separator, boolean keepSeparator) { - if (filename == null) { - return null; - } - int size = filename.length(); - if (size == 0) { - return filename; - } - int prefix = getPrefixLength(filename); - if (prefix < 0) { - return null; - } - - char[] array = new char[size + 2]; // +1 for possible extra slash, +2 for arraycopy - filename.getChars(0, filename.length(), array, 0); - - // fix separators throughout - char otherSeparator = separator == SYSTEM_SEPARATOR ? OTHER_SEPARATOR : SYSTEM_SEPARATOR; - for (int i = 0; i < array.length; i++) { - if (array[i] == otherSeparator) { - array[i] = separator; - } - } - - // add extra separator on the end to simplify code below - boolean lastIsDirectory = true; - if (array[size - 1] != separator) { - array[size++] = separator; - lastIsDirectory = false; - } - - // adjoining slashes - for (int i = prefix + 1; i < size; i++) { - if (array[i] == separator && array[i - 1] == separator) { - System.arraycopy(array, i, array, i - 1, size - i); - size--; - i--; - } - } - - // dot slash - for (int i = prefix + 1; i < size; i++) { - if (array[i] == separator && array[i - 1] == '.' && - (i == prefix + 1 || array[i - 2] == separator)) { - if (i == size - 1) { - lastIsDirectory = true; - } - System.arraycopy(array, i + 1, array, i - 1, size - i); - size -=2; - i--; - } - } - - // double dot slash - outer: - for (int i = prefix + 2; i < size; i++) { - if (array[i] == separator && array[i - 1] == '.' && array[i - 2] == '.' && - (i == prefix + 2 || array[i - 3] == separator)) { - if (i == prefix + 2) { - return null; - } - if (i == size - 1) { - lastIsDirectory = true; - } - int j; - for (j = i - 4 ; j >= prefix; j--) { - if (array[j] == separator) { - // remove b/../ from a/b/../c - System.arraycopy(array, i + 1, array, j + 1, size - i); - size -= i - j; - i = j + 1; - continue outer; - } - } - // remove a/../ from a/../c - System.arraycopy(array, i + 1, array, prefix, size - i); - size -= i + 1 - prefix; - i = prefix + 1; - } - } - - if (size <= 0) { // should never be less than 0 - return ""; - } - if (size <= prefix) { // should never be less than prefix - return new String(array, 0, size); - } - if (lastIsDirectory && keepSeparator) { - return new String(array, 0, size); // keep trailing separator - } - return new String(array, 0, size - 1); // lose trailing separator - } - - //----------------------------------------------------------------------- - /** - * Concatenates a filename to a base path using normal command line style rules. - *
- * The effect is equivalent to resultant directory after changing - * directory to the first argument, followed by changing directory to - * the second argument. - *
- * The first argument is the base path, the second is the path to concatenate.
- * The returned path is always normalized via {@link #normalize(String)},
- * thus ..
is handled.
- *
- * If pathToAdd
is absolute (has an absolute prefix), then
- * it will be normalized and returned.
- * Otherwise, the paths will be joined, normalized and returned.
- *
- * The output will be the same on both Unix and Windows except - * for the separator character. - *
- * /foo/ + bar --> /foo/bar - * /foo + bar --> /foo/bar - * /foo + /bar --> /bar - * /foo + C:/bar --> C:/bar - * /foo + C:bar --> C:bar (*) - * /foo/a/ + ../bar --> foo/bar - * /foo/ + ../../bar --> null - * /foo/ + /bar --> /bar - * /foo/.. + /bar --> /bar - * /foo + bar/c.txt --> /foo/bar/c.txt - * /foo/c.txt + bar --> /foo/c.txt/bar (!) - *- * (*) Note that the Windows relative drive prefix is unreliable when - * used with this method. - * (!) Note that the first parameter must be a path. If it ends with a name, then - * the name will be built into the concatenated path. If this might be a problem, - * use {@link #getFullPath(String)} on the base path argument. - * - * @param basePath the base path to attach to, always treated as a path - * @param fullFilenameToAdd the filename (or path) to attach to the base - * @return the concatenated path, or null if invalid - */ - public static String concat(String basePath, String fullFilenameToAdd) { - int prefix = getPrefixLength(fullFilenameToAdd); - if (prefix < 0) { - return null; - } - if (prefix > 0) { - return normalize(fullFilenameToAdd); - } - if (basePath == null) { - return null; - } - int len = basePath.length(); - if (len == 0) { - return normalize(fullFilenameToAdd); - } - char ch = basePath.charAt(len - 1); - if (isSeparator(ch)) { - return normalize(basePath + fullFilenameToAdd); - } else { - return normalize(basePath + '/' + fullFilenameToAdd); - } - } - - /** - * Determines whether the {@code parent} directory contains the {@code child} element (a file or directory). - *
- * The files names are expected to be normalized. - *
- * - * Edge cases: - *C:/
or ~/
.
- * - * This method will handle a file in either Unix or Windows format. - *
- * The prefix length includes the first slash in the full filename - * if applicable. Thus, it is possible that the length returned is greater - * than the length of the input string. - *
- * Windows: - * a\b\c.txt --> "" --> relative - * \a\b\c.txt --> "\" --> current drive absolute - * C:a\b\c.txt --> "C:" --> drive relative - * C:\a\b\c.txt --> "C:\" --> absolute - * \\server\a\b\c.txt --> "\\server\" --> UNC - * - * Unix: - * a/b/c.txt --> "" --> relative - * /a/b/c.txt --> "/" --> absolute - * ~/a/b/c.txt --> "~/" --> current user - * ~ --> "~/" --> current user (slash added) - * ~user/a/b/c.txt --> "~user/" --> named user - * ~user --> "~user/" --> named user (slash added) - *- *
- * The output will be the same irrespective of the machine that the code is running on. - * ie. both Unix and Windows prefixes are matched regardless. - * - * @param filename the filename to find the prefix in, null returns -1 - * @return the length of the prefix, -1 if invalid or null - */ - public static int getPrefixLength(String filename) { - if (filename == null) { - return -1; - } - int len = filename.length(); - if (len == 0) { - return 0; - } - char ch0 = filename.charAt(0); - if (ch0 == ':') { - return -1; - } - if (len == 1) { - if (ch0 == '~') { - return 2; // return a length greater than the input - } - return isSeparator(ch0) ? 1 : 0; - } else { - if (ch0 == '~') { - int posUnix = filename.indexOf(UNIX_SEPARATOR, 1); - int posWin = filename.indexOf(WINDOWS_SEPARATOR, 1); - if (posUnix == -1 && posWin == -1) { - return len + 1; // return a length greater than the input - } - posUnix = posUnix == -1 ? posWin : posUnix; - posWin = posWin == -1 ? posUnix : posWin; - return Math.min(posUnix, posWin) + 1; - } - char ch1 = filename.charAt(1); - if (ch1 == ':') { - ch0 = Character.toUpperCase(ch0); - if (ch0 >= 'A' && ch0 <= 'Z') { - if (len == 2 || isSeparator(filename.charAt(2)) == false) { - return 2; - } - return 3; - } - return -1; - - } else if (isSeparator(ch0) && isSeparator(ch1)) { - int posUnix = filename.indexOf(UNIX_SEPARATOR, 2); - int posWin = filename.indexOf(WINDOWS_SEPARATOR, 2); - if (posUnix == -1 && posWin == -1 || posUnix == 2 || posWin == 2) { - return -1; - } - posUnix = posUnix == -1 ? posWin : posUnix; - posWin = posWin == -1 ? posUnix : posWin; - return Math.min(posUnix, posWin) + 1; - } else { - return isSeparator(ch0) ? 1 : 0; - } - } - } - - /** - * Returns the index of the last directory separator character. - *
- * This method will handle a file in either Unix or Windows format. - * The position of the last forward or backslash is returned. - *
- * The output will be the same irrespective of the machine that the code is running on. - * - * @param filename the filename to find the last path separator in, null returns -1 - * @return the index of the last separator character, or -1 if there - * is no such character - */ - public static int indexOfLastSeparator(String filename) { - if (filename == null) { - return -1; - } - int lastUnixPos = filename.lastIndexOf(UNIX_SEPARATOR); - int lastWindowsPos = filename.lastIndexOf(WINDOWS_SEPARATOR); - return Math.max(lastUnixPos, lastWindowsPos); - } - - /** - * Returns the index of the last extension separator character, which is a dot. - *
- * This method also checks that there is no directory separator after the last dot. - * To do this it uses {@link #indexOfLastSeparator(String)} which will - * handle a file in either Unix or Windows format. - *
- * The output will be the same irrespective of the machine that the code is running on.
- *
- * @param filename the filename to find the last path separator in, null returns -1
- * @return the index of the last separator character, or -1 if there
- * is no such character
- */
- public static int indexOfExtension(String filename) {
- if (filename == null) {
- return -1;
- }
- int extensionPos = filename.lastIndexOf(EXTENSION_SEPARATOR);
- int lastSeparator = indexOfLastSeparator(filename);
- return lastSeparator > extensionPos ? -1 : extensionPos;
- }
-
- //-----------------------------------------------------------------------
- /**
- * Gets the prefix from a full filename, such as C:/
- * or ~/
.
- *
- * This method will handle a file in either Unix or Windows format. - * The prefix includes the first slash in the full filename where applicable. - *
- * Windows: - * a\b\c.txt --> "" --> relative - * \a\b\c.txt --> "\" --> current drive absolute - * C:a\b\c.txt --> "C:" --> drive relative - * C:\a\b\c.txt --> "C:\" --> absolute - * \\server\a\b\c.txt --> "\\server\" --> UNC - * - * Unix: - * a/b/c.txt --> "" --> relative - * /a/b/c.txt --> "/" --> absolute - * ~/a/b/c.txt --> "~/" --> current user - * ~ --> "~/" --> current user (slash added) - * ~user/a/b/c.txt --> "~user/" --> named user - * ~user --> "~user/" --> named user (slash added) - *- *
- * The output will be the same irrespective of the machine that the code is running on. - * ie. both Unix and Windows prefixes are matched regardless. - * - * @param filename the filename to query, null returns null - * @return the prefix of the file, null if invalid - */ - public static String getPrefix(String filename) { - if (filename == null) { - return null; - } - int len = getPrefixLength(filename); - if (len < 0) { - return null; - } - if (len > filename.length()) { - return filename + UNIX_SEPARATOR; // we know this only happens for unix - } - return filename.substring(0, len); - } - - /** - * Gets the path from a full filename, which excludes the prefix. - *
- * This method will handle a file in either Unix or Windows format. - * The method is entirely text based, and returns the text before and - * including the last forward or backslash. - *
- * C:\a\b\c.txt --> a\b\ - * ~/a/b/c.txt --> a/b/ - * a.txt --> "" - * a/b/c --> a/b/ - * a/b/c/ --> a/b/c/ - *- *
- * The output will be the same irrespective of the machine that the code is running on. - *
- * This method drops the prefix from the result. - * See {@link #getFullPath(String)} for the method that retains the prefix. - * - * @param filename the filename to query, null returns null - * @return the path of the file, an empty string if none exists, null if invalid - */ - public static String getPath(String filename) { - return doGetPath(filename, 1); - } - - /** - * Gets the path from a full filename, which excludes the prefix, and - * also excluding the final directory separator. - *
- * This method will handle a file in either Unix or Windows format. - * The method is entirely text based, and returns the text before the - * last forward or backslash. - *
- * C:\a\b\c.txt --> a\b - * ~/a/b/c.txt --> a/b - * a.txt --> "" - * a/b/c --> a/b - * a/b/c/ --> a/b/c - *- *
- * The output will be the same irrespective of the machine that the code is running on. - *
- * This method drops the prefix from the result. - * See {@link #getFullPathNoEndSeparator(String)} for the method that retains the prefix. - * - * @param filename the filename to query, null returns null - * @return the path of the file, an empty string if none exists, null if invalid - */ - public static String getPathNoEndSeparator(String filename) { - return doGetPath(filename, 0); - } - - /** - * Does the work of getting the path. - * - * @param filename the filename - * @param separatorAdd 0 to omit the end separator, 1 to return it - * @return the path - */ - private static String doGetPath(String filename, int separatorAdd) { - if (filename == null) { - return null; - } - int prefix = getPrefixLength(filename); - if (prefix < 0) { - return null; - } - int index = indexOfLastSeparator(filename); - int endIndex = index+separatorAdd; - if (prefix >= filename.length() || index < 0 || prefix >= endIndex) { - return ""; - } - return filename.substring(prefix, endIndex); - } - - /** - * Gets the full path from a full filename, which is the prefix + path. - *
- * This method will handle a file in either Unix or Windows format. - * The method is entirely text based, and returns the text before and - * including the last forward or backslash. - *
- * C:\a\b\c.txt --> C:\a\b\ - * ~/a/b/c.txt --> ~/a/b/ - * a.txt --> "" - * a/b/c --> a/b/ - * a/b/c/ --> a/b/c/ - * C: --> C: - * C:\ --> C:\ - * ~ --> ~/ - * ~/ --> ~/ - * ~user --> ~user/ - * ~user/ --> ~user/ - *- *
- * The output will be the same irrespective of the machine that the code is running on. - * - * @param filename the filename to query, null returns null - * @return the path of the file, an empty string if none exists, null if invalid - */ - public static String getFullPath(String filename) { - return doGetFullPath(filename, true); - } - - /** - * Gets the full path from a full filename, which is the prefix + path, - * and also excluding the final directory separator. - *
- * This method will handle a file in either Unix or Windows format. - * The method is entirely text based, and returns the text before the - * last forward or backslash. - *
- * C:\a\b\c.txt --> C:\a\b - * ~/a/b/c.txt --> ~/a/b - * a.txt --> "" - * a/b/c --> a/b - * a/b/c/ --> a/b/c - * C: --> C: - * C:\ --> C:\ - * ~ --> ~ - * ~/ --> ~ - * ~user --> ~user - * ~user/ --> ~user - *- *
- * The output will be the same irrespective of the machine that the code is running on. - * - * @param filename the filename to query, null returns null - * @return the path of the file, an empty string if none exists, null if invalid - */ - public static String getFullPathNoEndSeparator(String filename) { - return doGetFullPath(filename, false); - } - - /** - * Does the work of getting the path. - * - * @param filename the filename - * @param includeSeparator true to include the end separator - * @return the path - */ - private static String doGetFullPath(String filename, boolean includeSeparator) { - if (filename == null) { - return null; - } - int prefix = getPrefixLength(filename); - if (prefix < 0) { - return null; - } - if (prefix >= filename.length()) { - if (includeSeparator) { - return getPrefix(filename); // add end slash if necessary - } else { - return filename; - } - } - int index = indexOfLastSeparator(filename); - if (index < 0) { - return filename.substring(0, prefix); - } - int end = index + (includeSeparator ? 1 : 0); - if (end == 0) { - end++; - } - return filename.substring(0, end); - } - - /** - * Gets the name minus the path from a full filename. - *
- * This method will handle a file in either Unix or Windows format. - * The text after the last forward or backslash is returned. - *
- * a/b/c.txt --> c.txt - * a.txt --> a.txt - * a/b/c --> c - * a/b/c/ --> "" - *- *
- * The output will be the same irrespective of the machine that the code is running on. - * - * @param filename the filename to query, null returns null - * @return the name of the file without the path, or an empty string if none exists - */ - public static String getName(String filename) { - if (filename == null) { - return null; - } - int index = indexOfLastSeparator(filename); - return filename.substring(index + 1); - } - - /** - * Gets the base name, minus the full path and extension, from a full filename. - *
- * This method will handle a file in either Unix or Windows format. - * The text after the last forward or backslash and before the last dot is returned. - *
- * a/b/c.txt --> c - * a.txt --> a - * a/b/c --> c - * a/b/c/ --> "" - *- *
- * The output will be the same irrespective of the machine that the code is running on. - * - * @param filename the filename to query, null returns null - * @return the name of the file without the path, or an empty string if none exists - */ - public static String getBaseName(String filename) { - return removeExtension(getName(filename)); - } - - /** - * Gets the extension of a filename. - *
- * This method returns the textual part of the filename after the last dot. - * There must be no directory separator after the dot. - *
- * foo.txt --> "txt" - * a/b/c.jpg --> "jpg" - * a/b.txt/c --> "" - * a/b/c --> "" - *- *
- * The output will be the same irrespective of the machine that the code is running on. - * - * @param filename the filename to retrieve the extension of. - * @return the extension of the file or an empty string if none exists or {@code null} - * if the filename is {@code null}. - */ - public static String getExtension(String filename) { - if (filename == null) { - return null; - } - int index = indexOfExtension(filename); - if (index == -1) { - return ""; - } else { - return filename.substring(index + 1); - } - } - - //----------------------------------------------------------------------- - /** - * Removes the extension from a filename. - *
- * This method returns the textual part of the filename before the last dot. - * There must be no directory separator after the dot. - *
- * foo.txt --> foo - * a\b\c.jpg --> a\b\c - * a\b\c --> a\b\c - * a.b\c --> a.b\c - *- *
- * The output will be the same irrespective of the machine that the code is running on. - * - * @param filename the filename to query, null returns null - * @return the filename minus the extension - */ - public static String removeExtension(String filename) { - if (filename == null) { - return null; - } - int index = indexOfExtension(filename); - if (index == -1) { - return filename; - } else { - return filename.substring(0, index); - } - } - - //----------------------------------------------------------------------- - /** - * Checks whether two filenames are equal exactly. - *
- * No processing is performed on the filenames other than comparison, - * thus this is merely a null-safe case-sensitive equals. - * - * @param filename1 the first filename to query, may be null - * @param filename2 the second filename to query, may be null - * @return true if the filenames are equal, null equals null - * @see IOCase#SENSITIVE - */ - public static boolean equals(String filename1, String filename2) { - return equals(filename1, filename2, false, IOCase.SENSITIVE); - } - - /** - * Checks whether two filenames are equal using the case rules of the system. - *
- * No processing is performed on the filenames other than comparison. - * The check is case-sensitive on Unix and case-insensitive on Windows. - * - * @param filename1 the first filename to query, may be null - * @param filename2 the second filename to query, may be null - * @return true if the filenames are equal, null equals null - * @see IOCase#SYSTEM - */ - public static boolean equalsOnSystem(String filename1, String filename2) { - return equals(filename1, filename2, false, IOCase.SYSTEM); - } - - //----------------------------------------------------------------------- - /** - * Checks whether two filenames are equal after both have been normalized. - *
- * Both filenames are first passed to {@link #normalize(String)}. - * The check is then performed in a case-sensitive manner. - * - * @param filename1 the first filename to query, may be null - * @param filename2 the second filename to query, may be null - * @return true if the filenames are equal, null equals null - * @see IOCase#SENSITIVE - */ - public static boolean equalsNormalized(String filename1, String filename2) { - return equals(filename1, filename2, true, IOCase.SENSITIVE); - } - - /** - * Checks whether two filenames are equal after both have been normalized - * and using the case rules of the system. - *
- * Both filenames are first passed to {@link #normalize(String)}. - * The check is then performed case-sensitive on Unix and - * case-insensitive on Windows. - * - * @param filename1 the first filename to query, may be null - * @param filename2 the second filename to query, may be null - * @return true if the filenames are equal, null equals null - * @see IOCase#SYSTEM - */ - public static boolean equalsNormalizedOnSystem(String filename1, String filename2) { - return equals(filename1, filename2, true, IOCase.SYSTEM); - } - - /** - * Checks whether two filenames are equal, optionally normalizing and providing - * control over the case-sensitivity. - * - * @param filename1 the first filename to query, may be null - * @param filename2 the second filename to query, may be null - * @param normalized whether to normalize the filenames - * @param caseSensitivity what case sensitivity rule to use, null means case-sensitive - * @return true if the filenames are equal, null equals null - * @since 1.3 - */ - public static boolean equals( - String filename1, String filename2, - boolean normalized, IOCase caseSensitivity) { - - if (filename1 == null || filename2 == null) { - return filename1 == null && filename2 == null; - } - if (normalized) { - filename1 = normalize(filename1); - filename2 = normalize(filename2); - if (filename1 == null || filename2 == null) { - throw new NullPointerException( - "Error normalizing one or both of the file names"); - } - } - if (caseSensitivity == null) { - caseSensitivity = IOCase.SENSITIVE; - } - return caseSensitivity.checkEquals(filename1, filename2); - } - - //----------------------------------------------------------------------- - /** - * Checks whether the extension of the filename is that specified. - *
- * This method obtains the extension as the textual part of the filename - * after the last dot. There must be no directory separator after the dot. - * The extension check is case-sensitive on all platforms. - * - * @param filename the filename to query, null returns false - * @param extension the extension to check for, null or empty checks for no extension - * @return true if the filename has the specified extension - */ - public static boolean isExtension(String filename, String extension) { - if (filename == null) { - return false; - } - if (extension == null || extension.length() == 0) { - return indexOfExtension(filename) == -1; - } - String fileExt = getExtension(filename); - return fileExt.equals(extension); - } - - /** - * Checks whether the extension of the filename is one of those specified. - *
- * This method obtains the extension as the textual part of the filename - * after the last dot. There must be no directory separator after the dot. - * The extension check is case-sensitive on all platforms. - * - * @param filename the filename to query, null returns false - * @param extensions the extensions to check for, null checks for no extension - * @return true if the filename is one of the extensions - */ - public static boolean isExtension(String filename, String[] extensions) { - if (filename == null) { - return false; - } - if (extensions == null || extensions.length == 0) { - return indexOfExtension(filename) == -1; - } - String fileExt = getExtension(filename); - for (String extension : extensions) { - if (fileExt.equals(extension)) { - return true; - } - } - return false; - } - - /** - * Checks whether the extension of the filename is one of those specified. - *
- * This method obtains the extension as the textual part of the filename
- * after the last dot. There must be no directory separator after the dot.
- * The extension check is case-sensitive on all platforms.
- *
- * @param filename the filename to query, null returns false
- * @param extensions the extensions to check for, null checks for no extension
- * @return true if the filename is one of the extensions
- */
- public static boolean isExtension(String filename, Collection
- * The wildcard matcher uses the characters '?' and '*' to represent a
- * single or multiple (zero or more) wildcard characters.
- * This is the same as often found on Dos/Unix command lines.
- * The check is case-sensitive always.
- *
- * The wildcard matcher uses the characters '?' and '*' to represent a
- * single or multiple (zero or more) wildcard characters.
- * This is the same as often found on Dos/Unix command lines.
- * The check is case-sensitive on Unix and case-insensitive on Windows.
- *
- * The wildcard matcher uses the characters '?' and '*' to represent a
- * single or multiple (zero or more) wildcard characters.
- * N.B. the sequence "*?" does not work properly at present in match strings.
- *
- * @param filename the filename to match on
- * @param wildcardMatcher the wildcard string to match against
- * @param caseSensitivity what case sensitivity rule to use, null means case-sensitive
- * @return true if the filename matches the wilcard string
- * @since 1.3
- */
- public static boolean wildcardMatch(String filename, String wildcardMatcher, IOCase caseSensitivity) {
- if (filename == null && wildcardMatcher == null) {
- return true;
- }
- if (filename == null || wildcardMatcher == null) {
- return false;
- }
- if (caseSensitivity == null) {
- caseSensitivity = IOCase.SENSITIVE;
- }
- String[] wcs = splitOnTokens(wildcardMatcher);
- boolean anyChars = false;
- int textIdx = 0;
- int wcsIdx = 0;
- Stack
- * Different filing systems have different rules for case-sensitivity.
- * Windows is case-insensitive, Unix is case-sensitive.
- *
- * This class captures that difference, providing an enumeration to
- * control how filename comparisons should be performed. It also provides
- * methods that use the enumeration to perform comparisons.
- *
- * Wherever possible, you should use the
- * Note: This only caters for Windows and Unix. Other operating
- * systems (e.g. OSX and OpenVMS) are treated as case sensitive if they use the
- * Unix file separator and case-insensitive if they use the Windows file separator
- * (see {@link java.io.File#separatorChar}).
- *
- * If you derialize this constant of Windows, and deserialize on Unix, or vice
- * versa, then the value of the case-sensitivity flag will change.
- */
- public static final IOCase SYSTEM = new IOCase("System", !FilenameUtils.isSystemWindows());
-
- /** Serialization version. */
- private static final long serialVersionUID = -6343169151696340687L;
-
- /** The enumeration name. */
- private final String name;
-
- /** The sensitivity flag. */
- private final transient boolean sensitive;
-
- //-----------------------------------------------------------------------
- /**
- * Factory method to create an IOCase from a name.
- *
- * @param name the name to find
- * @return the IOCase object
- * @throws IllegalArgumentException if the name is invalid
- */
- public static IOCase forName(String name) {
- if (IOCase.SENSITIVE.name.equals(name)){
- return IOCase.SENSITIVE;
- }
- if (IOCase.INSENSITIVE.name.equals(name)){
- return IOCase.INSENSITIVE;
- }
- if (IOCase.SYSTEM.name.equals(name)){
- return IOCase.SYSTEM;
- }
- throw new IllegalArgumentException("Invalid IOCase name: " + name);
- }
-
- //-----------------------------------------------------------------------
- /**
- * Private constructor.
- *
- * @param name the name
- * @param sensitive the sensitivity
- */
- private IOCase(String name, boolean sensitive) {
- this.name = name;
- this.sensitive = sensitive;
- }
-
- /**
- * Replaces the enumeration from the stream with a real one.
- * This ensures that the correct flag is set for SYSTEM.
- *
- * @return the resolved object
- */
- private Object readResolve() {
- return forName(this.name);
- }
-
- //-----------------------------------------------------------------------
- /**
- * Gets the name of the constant.
- *
- * @return the name of the constant
- */
- public String getName() {
- return this.name;
- }
-
- /**
- * Does the object represent case sensitive comparison.
- *
- * @return true if case sensitive
- */
- public boolean isCaseSensitive() {
- return this.sensitive;
- }
-
- //-----------------------------------------------------------------------
- /**
- * Compares two strings using the case-sensitivity rule.
- *
- * This method mimics {@link String#compareTo} but takes case-sensitivity
- * into account.
- *
- * @param str1 the first string to compare, not null
- * @param str2 the second string to compare, not null
- * @return true if equal using the case rules
- * @throws NullPointerException if either string is null
- */
- public int checkCompareTo(String str1, String str2) {
- if (str1 == null || str2 == null) {
- throw new NullPointerException("The strings must not be null");
- }
- return this.sensitive ? str1.compareTo(str2) : str1.compareToIgnoreCase(str2);
- }
-
- /**
- * Compares two strings using the case-sensitivity rule.
- *
- * This method mimics {@link String#equals} but takes case-sensitivity
- * into account.
- *
- * @param str1 the first string to compare, not null
- * @param str2 the second string to compare, not null
- * @return true if equal using the case rules
- * @throws NullPointerException if either string is null
- */
- public boolean checkEquals(String str1, String str2) {
- if (str1 == null || str2 == null) {
- throw new NullPointerException("The strings must not be null");
- }
- return this.sensitive ? str1.equals(str2) : str1.equalsIgnoreCase(str2);
- }
-
- /**
- * Checks if one string starts with another using the case-sensitivity rule.
- *
- * This method mimics {@link String#startsWith(String)} but takes case-sensitivity
- * into account.
- *
- * @param str the string to check, not null
- * @param start the start to compare against, not null
- * @return true if equal using the case rules
- * @throws NullPointerException if either string is null
- */
- public boolean checkStartsWith(String str, String start) {
- return str.regionMatches(!this.sensitive, 0, start, 0, start.length());
- }
-
- /**
- * Checks if one string ends with another using the case-sensitivity rule.
- *
- * This method mimics {@link String#endsWith} but takes case-sensitivity
- * into account.
- *
- * @param str the string to check, not null
- * @param end the end to compare against, not null
- * @return true if equal using the case rules
- * @throws NullPointerException if either string is null
- */
- public boolean checkEndsWith(String str, String end) {
- int endLen = end.length();
- return str.regionMatches(!this.sensitive, str.length() - endLen, end, 0, endLen);
- }
-
- /**
- * Checks if one string contains another starting at a specific index using the
- * case-sensitivity rule.
- *
- * This method mimics parts of {@link String#indexOf(String, int)}
- * but takes case-sensitivity into account.
- *
- * @param str the string to check, not null
- * @param strStartIndex the index to start at in str
- * @param search the start to search for, not null
- * @return the first index of the search String,
- * -1 if no match or {@code null} string input
- * @throws NullPointerException if either string is null
- * @since 2.0
- */
- public int checkIndexOf(String str, int strStartIndex, String search) {
- int endIndex = str.length() - search.length();
- if (endIndex >= strStartIndex) {
- for (int i = strStartIndex; i <= endIndex; i++) {
- if (checkRegionMatches(str, i, search)) {
- return i;
- }
- }
- }
- return -1;
- }
-
- /**
- * Checks if one string contains another at a specific index using the case-sensitivity rule.
- *
- * This method mimics parts of {@link String#regionMatches(boolean, int, String, int, int)}
- * but takes case-sensitivity into account.
- *
- * @param str the string to check, not null
- * @param strStartIndex the index to start at in str
- * @param search the start to search for, not null
- * @return true if equal using the case rules
- * @throws NullPointerException if either string is null
- */
- public boolean checkRegionMatches(String str, int strStartIndex, String search) {
- return str.regionMatches(!this.sensitive, strStartIndex, search, 0, search.length());
- }
-
- //-----------------------------------------------------------------------
- /**
- * Gets a string describing the sensitivity.
- *
- * @return a string describing the sensitivity
- */
- @Override
- public String toString() {
- return this.name;
- }
-
-}
\ No newline at end of file
diff --git a/Dorkbox-Util/src/dorkbox/util/process/JavaProcessBuilder.java b/Dorkbox-Util/src/dorkbox/util/process/JavaProcessBuilder.java
index e948e0a..7107108 100644
--- a/Dorkbox-Util/src/dorkbox/util/process/JavaProcessBuilder.java
+++ b/Dorkbox-Util/src/dorkbox/util/process/JavaProcessBuilder.java
@@ -6,7 +6,7 @@ import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
-import dorkbox.util.FilenameUtils;
+import dorkbox.util.FileUtil;
import dorkbox.util.OS;
/**
@@ -79,7 +79,7 @@ public class JavaProcessBuilder extends ShellProcessBuilder {
for (String classpathEntry : this.classpathEntries) {
try {
// make sure the classpath is ABSOLUTE pathname
- classpathEntry = FilenameUtils.normalize(new File(classpathEntry).getAbsolutePath());
+ classpathEntry = FileUtil.normalize(new File(classpathEntry).getAbsolutePath());
// fix a nasty problem when spaces aren't properly escaped!
classpathEntry = classpathEntry.replaceAll(" ", "\\ ");
@@ -204,8 +204,8 @@ public class JavaProcessBuilder extends ShellProcessBuilder {
// even though the former is a symlink to the latter! To work around this, see if the
// desired jvm is in fact pointed to by /usr/bin/java and, if so, use that instead.
if (OS.isMacOsX()) {
- String localVM = FilenameUtils.normalize(new File("/usr/bin/java").getAbsolutePath());
- String vmCheck = FilenameUtils.normalize(new File(vmpath).getAbsolutePath());
+ String localVM = FileUtil.normalize(new File("/usr/bin/java").getAbsolutePath());
+ String vmCheck = FileUtil.normalize(new File(vmpath).getAbsolutePath());
if (localVM.equals(vmCheck)) {
vmpath = "/usr/bin/java";
}
diff --git a/Dorkbox-Util/src/dorkbox/util/process/ProcessProxy.java b/Dorkbox-Util/src/dorkbox/util/process/ProcessProxy.java
index 8d4dd60..4ced31c 100644
--- a/Dorkbox-Util/src/dorkbox/util/process/ProcessProxy.java
+++ b/Dorkbox-Util/src/dorkbox/util/process/ProcessProxy.java
@@ -38,7 +38,6 @@ public class ProcessProxy extends Thread {
}
} else {
while ((readInt = this.is.read()) != -1) {
- System.err.println("READ : " + (char)readInt);
this.os.write(readInt);
// always flush
this.os.flush();
- * wildcardMatch("c.txt", "*.txt") --> true
- * wildcardMatch("c.txt", "*.jpg") --> false
- * wildcardMatch("a/b/c.txt", "a/b/*") --> true
- * wildcardMatch("c.txt", "*.???") --> true
- * wildcardMatch("c.txt", "*.????") --> false
- *
- * N.B. the sequence "*?" does not work properly at present in match strings.
- *
- * @param filename the filename to match on
- * @param wildcardMatcher the wildcard string to match against
- * @return true if the filename matches the wilcard string
- * @see IOCase#SENSITIVE
- */
- public static boolean wildcardMatch(String filename, String wildcardMatcher) {
- return wildcardMatch(filename, wildcardMatcher, IOCase.SENSITIVE);
- }
-
- /**
- * Checks a filename to see if it matches the specified wildcard matcher
- * using the case rules of the system.
- *
- * wildcardMatch("c.txt", "*.txt") --> true
- * wildcardMatch("c.txt", "*.jpg") --> false
- * wildcardMatch("a/b/c.txt", "a/b/*") --> true
- * wildcardMatch("c.txt", "*.???") --> true
- * wildcardMatch("c.txt", "*.????") --> false
- *
- * N.B. the sequence "*?" does not work properly at present in match strings.
- *
- * @param filename the filename to match on
- * @param wildcardMatcher the wildcard string to match against
- * @return true if the filename matches the wilcard string
- * @see IOCase#SYSTEM
- */
- public static boolean wildcardMatchOnSystem(String filename, String wildcardMatcher) {
- return wildcardMatch(filename, wildcardMatcher, IOCase.SYSTEM);
- }
-
- /**
- * Checks a filename to see if it matches the specified wildcard matcher
- * allowing control over case-sensitivity.
- * check
methods in this
- * class to compare filenames.
- *
- * @version $Id: IOCase.java 1307459 2012-03-30 15:11:44Z ggregory $
- * @since 1.3
- */
-public final class IOCase implements Serializable {
-
- /**
- * The constant for case sensitive regardless of operating system.
- */
- public static final IOCase SENSITIVE = new IOCase("Sensitive", true);
-
- /**
- * The constant for case insensitive regardless of operating system.
- */
- public static final IOCase INSENSITIVE = new IOCase("Insensitive", false);
-
- /**
- * The constant for case sensitivity determined by the current operating system.
- * Windows is case-insensitive when comparing filenames, Unix is case-sensitive.
- *