Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/windows/classes/sun/nio/fs/WindowsPathParser.java
32288 views
/*1* Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.nio.fs;2627import java.nio.file.InvalidPathException;2829/**30* A parser of Windows path strings31*/3233class WindowsPathParser {34private WindowsPathParser() { }3536/**37* The result of a parse operation38*/39static class Result {40private final WindowsPathType type;41private final String root;42private final String path;4344Result(WindowsPathType type, String root, String path) {45this.type = type;46this.root = root;47this.path = path;48}4950/**51* The path type52*/53WindowsPathType type() {54return type;55}5657/**58* The root component59*/60String root() {61return root;62}6364/**65* The normalized path (includes root)66*/67String path() {68return path;69}70}7172/**73* Parses the given input as a Windows path74*/75static Result parse(String input) {76return parse(input, true);77}7879/**80* Parses the given input as a Windows path where it is known that the81* path is already normalized.82*/83static Result parseNormalizedPath(String input) {84return parse(input, false);85}8687/**88* Parses the given input as a Windows path.89*90* @param requireToNormalize91* Indicates if the path requires to be normalized92*/93private static Result parse(String input, boolean requireToNormalize) {94String root = "";95WindowsPathType type = null;9697int len = input.length();98int off = 0;99if (len > 1) {100char c0 = input.charAt(0);101char c1 = input.charAt(1);102char c = 0;103int next = 2;104if (isSlash(c0) && isSlash(c1)) {105// UNC: We keep the first two slash, collapse all the106// following, then take the hostname and share name out,107// meanwhile collapsing all the redundant slashes.108type = WindowsPathType.UNC;109off = nextNonSlash(input, next, len);110next = nextSlash(input, off, len);111if (off == next)112throw new InvalidPathException(input, "UNC path is missing hostname");113String host = input.substring(off, next); //host114off = nextNonSlash(input, next, len);115next = nextSlash(input, off, len);116if (off == next)117throw new InvalidPathException(input, "UNC path is missing sharename");118root = "\\\\" + host + "\\" + input.substring(off, next) + "\\";119off = next;120} else {121if (isLetter(c0) && c1 == ':') {122char c2;123if (len > 2 && isSlash(c2 = input.charAt(2))) {124// avoid concatenation when root is "D:\"125if (c2 == '\\') {126root = input.substring(0, 3);127} else {128root = input.substring(0, 2) + '\\';129}130off = 3;131type = WindowsPathType.ABSOLUTE;132} else {133root = input.substring(0, 2);134off = 2;135type = WindowsPathType.DRIVE_RELATIVE;136}137}138}139}140if (off == 0) {141if (len > 0 && isSlash(input.charAt(0))) {142type = WindowsPathType.DIRECTORY_RELATIVE;143root = "\\";144} else {145type = WindowsPathType.RELATIVE;146}147}148149if (requireToNormalize) {150StringBuilder sb = new StringBuilder(input.length());151sb.append(root);152return new Result(type, root, normalize(sb, input, off));153} else {154return new Result(type, root, input);155}156}157158/**159* Remove redundant slashes from the rest of the path, forcing all slashes160* into the preferred slash.161*/162private static String normalize(StringBuilder sb, String path, int off) {163int len = path.length();164off = nextNonSlash(path, off, len);165int start = off;166char lastC = 0;167while (off < len) {168char c = path.charAt(off);169if (isSlash(c)) {170if (lastC == ' ')171throw new InvalidPathException(path,172"Trailing char <" + lastC + ">",173off - 1);174sb.append(path, start, off);175off = nextNonSlash(path, off, len);176if (off != len) //no slash at the end of normalized path177sb.append('\\');178start = off;179} else {180if (isInvalidPathChar(c))181throw new InvalidPathException(path,182"Illegal char <" + c + ">",183off);184lastC = c;185off++;186}187}188if (start != off) {189if (lastC == ' ')190throw new InvalidPathException(path,191"Trailing char <" + lastC + ">",192off - 1);193sb.append(path, start, off);194}195return sb.toString();196}197198private static final boolean isSlash(char c) {199return (c == '\\') || (c == '/');200}201202private static final int nextNonSlash(String path, int off, int end) {203while (off < end && isSlash(path.charAt(off))) { off++; }204return off;205}206207private static final int nextSlash(String path, int off, int end) {208char c;209while (off < end && !isSlash(c=path.charAt(off))) {210if (isInvalidPathChar(c))211throw new InvalidPathException(path,212"Illegal character [" + c + "] in path",213off);214off++;215}216return off;217}218219private static final boolean isLetter(char c) {220return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'));221}222223// Reserved characters for window path name224private static final String reservedChars = "<>:\"|?*";225private static final boolean isInvalidPathChar(char ch) {226return ch < '\u0020' || reservedChars.indexOf(ch) != -1;227}228}229230231