/* * 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; } }