--- /dev/null 2018-09-07 16:39:11.960000000 -0400 +++ new/src/java.base/share/classes/jdk/internal/util/PathParser.java 2018-09-10 14:12:32.071490752 -0400 @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.util; + +import sun.security.action.GetPropertyAction; + +import java.io.File; + +/** + * Parse path strings and return a List of paths and path strings. + * Implementation relocated and improved from ClassLoader. + */ +public class PathParser { + + private static final boolean allowsQuotedPathElements = initQuotesAllowed(); + + private static boolean initQuotesAllowed() { + return GetPropertyAction.privilegedGetProperty("os.name").contains("Windows"); + } + + /** + * Returns an array of path strings parsed from a string. + * Empty paths, identified by leading, trailing, and adjacent separator characters, + * can be omitted or replaced with a non-null provided path. + *

+ * The string is split using {@link File#pathSeparator}. + * The {@code pathSeparator} character can be included in a path + * on operating systems that support quoting segments of the string. + * + * @param path a string containing paths separated by the {@link File#pathSeparator} + * @param emptyPath a path to replace an empty path or {@code null} to omit empty paths + * @return an non-null array of strings for each path + * @implNote On Windows, quoting of path segments is supported. Each {@link File#pathSeparator} + * between pairs of quotation marks (@code 'U+0022') is considered an ordinary character + * and the quotes are omitted from the path. + * An unmatched quote is matched by the end of the string. + * + * @see java.nio.file.Paths#pathToStrings(String) + * @see java.nio.file.Paths#pathToPaths(String) + */ + public static String[] parsePath(String path, String emptyPath) { + char ps = File.pathSeparatorChar; + int psCount = 0; + int emptyCount = 0; + if (allowsQuotedPathElements && + path.indexOf('\"') >= 0) { + // First, remove quotes put around quoted parts of paths. + // Second, use a quotation mark as a new path separator. + // This will preserve any quoted old path separators. + int ldLen = path.length(); + char[] buf = new char[ldLen]; + int bufLen = 0; + int i, j; + for (i = 0, j = 0; i < ldLen; ++i) { + char ch = path.charAt(i); + if (ch == '\"') { + while (++i < ldLen && + (ch = path.charAt(i)) != '\"') { + buf[bufLen++] = ch; + } + } else { + if (ch == ps) { + psCount++; + emptyCount += (j < bufLen) ? 0 : 1; // count empty elements + ch = '\"'; + j = bufLen + 1; // start of next element + } + buf[bufLen++] = ch; + } + } + emptyCount += (j < bufLen) ? 0 : 1; + path = new String(buf, 0, bufLen); + ldLen = bufLen; + ps = '\"'; + } else { + int i, j; + for (i = path.indexOf(ps), j = 0; i >= 0; + j = i + 1, i = path.indexOf(ps, j)) { + psCount++; + emptyCount += (j < i) ? 0 : 1; // count empty elements + } + emptyCount += (j < path.length()) ? 0 : 1; + } + + if (emptyPath == null) { + // Do not save space to replace empty elements + psCount -= emptyCount; + } + + String[] paths = new String[psCount + 1]; + int next = 0; + int startPath = 0; + int endPath; + for (endPath = path.indexOf(ps); endPath >= 0; + startPath = endPath + 1, endPath = path.indexOf(ps, startPath)) { + if (endPath > startPath) { + paths[next++] = path.substring(startPath, endPath); + } else if (emptyPath != null) { + paths[next++] = emptyPath; + } + } + if (path.length() > startPath) { + paths[next] = path.substring(startPath); + } else if (emptyPath != null) { + paths[next] = emptyPath; + } + return paths; + } +}