--- old/src/java.base/share/classes/java/nio/file/Path.java 2018-02-13 17:25:19.000000000 -0800 +++ new/src/java.base/share/classes/java/nio/file/Path.java 2018-02-13 17:25:19.000000000 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -30,6 +30,8 @@ import java.net.URI; import java.util.Iterator; import java.util.NoSuchElementException; +import java.util.Objects; +import java.util.stream.Stream; /** * An object that may be used to locate a file in a file system. It will @@ -323,6 +325,43 @@ } /** + * Returns whether the extension of this path is in a specified list. + * The extension is that portion of the path after the last dot + * ({@code '.'}). If this path is empty, ends with a dot, or has a + * {@link FileSystem#getSeparator() name-separator} after the last dot, + * or the parameter is empty, then this method returns {@code false}. + * Any arguments in the parameter which are either empty or contain a + * dot are ignored. + * + * @param extensions + * the extensions to be checked + * + * @return whether this path has one of the specified extensions + */ + default boolean hasExtension(String... extensions) { + Objects.requireNonNull(extensions); + + String path = toString(); + if (path.isEmpty()) { + return false; + } + + int lastDot = path.lastIndexOf("."); + if (lastDot == path.length() - 1) { + return false; + } + + String separator = getFileSystem().getSeparator(); + if (path.indexOf(separator, lastDot) != -1) { + return false; + } + + return Stream.of(extensions) + .filter(e -> !e.isEmpty() && !e.contains(".")) + .anyMatch(path::endsWith); + } + + /** * Returns a path that is this path with redundant name elements eliminated. * *

The precise definition of this method is implementation dependent but --- old/src/java.base/share/classes/sun/nio/fs/Util.java 2018-02-13 17:25:19.000000000 -0800 +++ new/src/java.base/share/classes/sun/nio/fs/Util.java 2018-02-13 17:25:19.000000000 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -25,9 +25,10 @@ package sun.nio.fs; -import java.util.*; -import java.nio.file.*; import java.nio.charset.Charset; +import java.nio.file.LinkOption; +import java.util.HashSet; +import java.util.Set; import sun.security.action.GetPropertyAction; /** @@ -48,22 +49,29 @@ } /** - * Encodes the given String into a sequence of bytes using the {@code Charset} - * specified by the sun.jnu.encoding property. + * Encodes the given String into a sequence of bytes using the + * {@code Charset} specified by the sun.jnu.encoding property. */ static byte[] toBytes(String s) { return s.getBytes(jnuEncoding); } /** - * Constructs a new String by decoding the specified array of bytes using the - * {@code Charset} specified by the sun.jnu.encoding property. + * Constructs a new String by decoding the specified array of bytes + * using the {@code Charset} specified by the sun.jnu.encoding property. + */ + static String toString(byte[] bytes, int offset, int length) { + return new String(bytes, offset, length, jnuEncoding); + } + + /** + * Constructs a new String by decoding the specified sub-array of bytes + * using the {@code Charset} specified by the sun.jnu.encoding property. */ static String toString(byte[] bytes) { return new String(bytes, jnuEncoding); } - /** * Splits a string around the given character. The array returned by this * method contains each substring that is terminated by the character. Use --- old/src/java.base/unix/classes/sun/nio/fs/UnixPath.java 2018-02-13 17:25:20.000000000 -0800 +++ new/src/java.base/unix/classes/sun/nio/fs/UnixPath.java 2018-02-13 17:25:20.000000000 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -25,16 +25,31 @@ package sun.nio.fs; -import java.nio.*; -import java.nio.file.*; -import java.nio.charset.*; -import java.io.*; -import java.net.URI; -import java.util.*; +import java.io.IOException; import java.lang.ref.SoftReference; - -import static sun.nio.fs.UnixNativeDispatcher.*; -import static sun.nio.fs.UnixConstants.*; +import java.net.URI; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; +import java.nio.file.InvalidPathException; +import java.nio.file.LinkOption; +import java.nio.file.ProviderMismatchException; +import java.nio.file.Path; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import java.util.Arrays; +import java.util.Objects; +import java.util.stream.Stream; + +import static sun.nio.fs.UnixConstants.EINVAL; +import static sun.nio.fs.UnixConstants.ELOOP; +import static sun.nio.fs.UnixConstants.O_NOFOLLOW; +import static sun.nio.fs.UnixConstants.O_RDONLY; +import static sun.nio.fs.UnixNativeDispatcher.open; +import static sun.nio.fs.UnixNativeDispatcher.realpath; /** * Solaris/Linux implementation of java.nio.file.Path @@ -739,6 +754,40 @@ return true; } + private String getExtension() { + final int length = path.length; + int index = length; + int lastDotIndex = -1; + while (--index >= 0) { + byte b = path[index]; + if (b == '.') { + lastDotIndex = index; + break; + } else if (b == '/') { + break; + } + } + + if (lastDotIndex < 0 || lastDotIndex == length - 1) { + return null; + } + + int offset = lastDotIndex + 1; + return Util.toString(path, offset, length - offset); + } + + @Override + public boolean hasExtension(String... extensions) { + Objects.requireNonNull(extensions); + + String extension = getExtension(); + if (extension == null) { + return false; + } + + return Stream.of(extensions).anyMatch(extension::equals); + } + @Override public int compareTo(Path other) { int len1 = path.length; --- old/test/jdk/java/nio/file/Path/PathOps.java 2018-02-13 17:25:20.000000000 -0800 +++ new/test/jdk/java/nio/file/Path/PathOps.java 2018-02-13 17:25:20.000000000 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -22,7 +22,7 @@ */ /* @test - * @bug 4313887 6838333 6925932 7006126 8037945 8072495 8140449 + * @bug 4313887 6838333 6925932 7006126 8037945 8057113 8072495 8140449 * @summary Unit test for java.nio.file.Path path operations */ @@ -156,6 +156,35 @@ return this; } + PathOps ext(String... extensions) { + out.format("test hasExtension {%s", extensions[0]); + final int len = extensions.length; + for (int i = 1; i < len; i++) { + out.format(", %s", extensions[i]); + } + out.format("}%n"); + checkPath(); + check(path.hasExtension(extensions), true); + return this; + } + + PathOps notExt(String... extensions) { + if (extensions == null) { + out.format("test not hasExtension for empty parameter"); + extensions = new String[0]; + } else { + out.format("test not hasExtension {%s", extensions[0]); + final int len = extensions.length; + for (int i = 1; i < len; i++) { + out.format(", %s", extensions[i]); + } + out.format("}%n"); + } + checkPath(); + check(path.hasExtension(extensions), false); + return this; + } + PathOps makeAbsolute() { this.path = path.toAbsolutePath(); return this; @@ -413,6 +442,30 @@ .ends("") .notEnds("\\"); + // hasExtension + test("") + .notExt(null) + .notExt("", ".", "\\") + .notExt("mp3", "mp4"); + test(".") + .notExt(null) + .notExt("", ".", "\\") + .notExt("mp3", "mp4"); + test("./foo/") + .notExt(null) + .notExt("", ".", "\\") + .notExt("foo") + .notExt("mp3", "mp4"); + test("image.jpg") + .ext("jpg") + .ext("jpg", "JPG") + .ext("JPG", "jpg") + .ext("png", "PNG", "tiff", "JPG", "jpg") + .notExt(null) + .notExt("", ".", "\\") + .notExt(".jpg") + .notExt("bmp", "BMP"); + // elements test("C:\\a\\b\\c") .element(0, "a") @@ -1563,6 +1616,30 @@ .ends("") .notEnds("/"); + // hasExtension + test("") + .notExt(null) + .notExt("", ".", "/") + .notExt("mp3", "mp4"); + test(".") + .notExt(null) + .notExt("", ".", "/") + .notExt("mp3", "mp4"); + test("./foo/") + .notExt(null) + .notExt("", ".", "/") + .notExt("foo") + .notExt("mp3", "mp4"); + test("image.jpg") + .ext("jpg") + .ext("jpg", "JPG") + .ext("JPG", "jpg") + .ext("png", "PNG", "tiff", "JPG", "jpg") + .notExt(null) + .notExt("", ".", "/") + .notExt(".jpg") + .notExt("bmp", "BMP"); + // elements test("a/b/c") .element(0, "a") @@ -2074,6 +2151,11 @@ } catch (NullPointerException npe) { } + try { + path.hasExtension((String[])null); + throw new RuntimeException("NullPointerException not thrown"); + } catch (NullPointerException npe) { + } } public static void main(String[] args) {