diff --git a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/URIUtilTest.java b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/URIUtilTest.java index 08f7f87d979..86aec62a15c 100644 --- a/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/URIUtilTest.java +++ b/bundles/org.eclipse.equinox.common.tests/src/org/eclipse/equinox/common/tests/URIUtilTest.java @@ -19,6 +19,7 @@ import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.junit.Assume.assumeTrue; import java.io.File; import java.io.InputStream; @@ -26,6 +27,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.net.URL; +import java.nio.file.Path; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.IPath; @@ -97,9 +99,7 @@ public void testToFile() { */ @Test public void testToFileUNC() throws URISyntaxException { - if (!WINDOWS) { - return; - } + assumeTrue(WINDOWS); // UNC paths URI path = new URI("file://HOST/some/path"); File result = URIUtil.toFile(path); @@ -187,6 +187,38 @@ public void testURLtoURI() throws MalformedURLException, URISyntaxException { assertEquals("3.2", new URI("file:////SERVER/some/path"), URIUtil.toURI(new URL("file:////SERVER/some/path"))); } + @Test + public void testURLtoPath() throws MalformedURLException { + + assertThrows(IllegalArgumentException.class, () -> URIUtil.toFilePath(new URL("http://foo.bar"))); + + assertEquals(Path.of("C:/foo/bar.txt"), URIUtil.toFilePath(new URL("file:/C:/foo/bar.txt"))); + assertEquals(Path.of("C:/foo/bar.txt"), URIUtil.toFilePath(new URL("file:///C:/foo/bar.txt"))); + + // Not escaped special characters like spaces, % or # + assertEquals(Path.of("C:/foo/a b.txt"), URIUtil.toFilePath(new URL("file:/C:/foo/a b.txt"))); + assertEquals(Path.of("C:/foo/a#b c.txt"), URIUtil.toFilePath(new URL("file:/C:/foo/a#b c.txt"))); + assertEquals(Path.of("C:/foo/a%b.txt"), URIUtil.toFilePath(new URL("file:/C:/foo/a%b.txt"))); + assertEquals(Path.of("C:/foo/bar#my-query"), URIUtil.toFilePath(new URL("file:/C:/foo/bar#my-query"))); + + // UNC paths (with not escaped spaces and %) + assertEquals(Path.of("////SERVER/some/path"), URIUtil.toFilePath(new URL("file://SERVER/some/path"))); + assertEquals(Path.of("////SERVER/some/path"), URIUtil.toFilePath(new URL("file:////SERVER/some/path"))); + assertEquals(Path.of("////SERVER/a b/path"), URIUtil.toFilePath(new URL("file://SERVER/a b/path"))); + assertEquals(Path.of("////SERVER/a#b c/path"), URIUtil.toFilePath(new URL("file:////SERVER/a#b c/path"))); + assertEquals(Path.of("////SERVER/some/a%b.txt"), URIUtil.toFilePath(new URL("file://SERVER/some/a%b.txt"))); + assertEquals(Path.of("////SERVER/some/a%b.txt"), URIUtil.toFilePath(new URL("file:////SERVER/some/a%b.txt"))); + + + // TODO: split the following? Make this a Windows only test case and create a + // separate UNIX test-case? + assumeTrue(WINDOWS); + assertEquals(Path.of("C:/foo/bar.txt"), URIUtil.toFilePath(new URL("file:c:/foo/bar.txt"))); + assertEquals(Path.of("C:/foo/bar.txt"), URIUtil.toFilePath(new URL("file:/c:/foo/bar.txt"))); + + assertEquals(Path.of("foo/bar.txt"), URIUtil.toFilePath(new URL("file:foo/bar.txt"))); + } + /** * Tests for {@link URIUtil#toURL(java.net.URI)}. */ @@ -210,9 +242,7 @@ public void testURItoURL() throws MalformedURLException, URISyntaxException { */ @Test public void testWindowsPathsFromURI() throws MalformedURLException, URISyntaxException { - if (!WINDOWS) { - return; - } + assumeTrue(WINDOWS); assertEquals("1.1", new URI("file:/c:/foo/bar.txt"), URIUtil.toURI(new URL("file:c:/foo/bar.txt"))); assertEquals("1.2", new URI("file:/c:/foo/bar.txt"), URIUtil.toURI(new URL("file:/c:/foo/bar.txt"))); } @@ -223,9 +253,7 @@ public void testWindowsPathsFromURI() throws MalformedURLException, URISyntaxExc */ @Test public void testWindowsPathsFromString() throws URISyntaxException { - if (!WINDOWS) { - return; - } + assumeTrue(WINDOWS); assertEquals("1.1", new URI("file:/c:/foo/bar.txt"), URIUtil.fromString("file:c:/foo/bar.txt")); assertEquals("1.2", new URI("file:/c:/foo/bar.txt"), URIUtil.fromString("file:/c:/foo/bar.txt")); } @@ -239,22 +267,13 @@ public void testFileWithSpaces() throws MalformedURLException, URISyntaxExceptio File fileWithSpaces = new File("/c:/with spaces/goo"); URI correctURI = fileWithSpaces.toURI(); URL fileURL = fileWithSpaces.toURL(); - URI fileURI = null; - try { - fileURI = fileURL.toURI(); - fail(); - } catch (URISyntaxException e) { - fileURI = URIUtil.toURI(fileURL); - } - assertEquals("1.1", correctURI, fileURI); - try { - fileURI = new URI(fileURL.toString()); - fail(); - } catch (URISyntaxException e) { - fileURI = URIUtil.fromString(fileURL.toString()); - } - assertEquals("1.2", correctURI, fileURI); + assertThrows(URISyntaxException.class, () -> fileURL.toURI()); + assertEquals("1.1", correctURI, URIUtil.toURI(fileURL)); + + String fileURLString = fileURL.toString(); + assertThrows(URISyntaxException.class, () -> new URI(fileURLString)); + assertEquals("1.2", correctURI, URIUtil.fromString(fileURLString)); } /** @@ -365,9 +384,8 @@ public void testBug286339() throws URISyntaxException { @Test public void testAppendWindows() throws URISyntaxException { - if (!WINDOWS) { - return; - } + assumeTrue(WINDOWS); + URI base = new URI("file:/C:/a%20b"); URI result = URIUtil.append(base, "file.txt"); assertEquals("1.0", "file:/C:/a%20b/file.txt", result.toString()); @@ -440,9 +458,7 @@ public void testSameURI() throws URISyntaxException { @Test public void testSameURIWindows() throws URISyntaxException { - if (!WINDOWS) { - return; - } + assumeTrue(WINDOWS); // device and case variants assertTrue("1.0", URIUtil.sameURI(new URI("file:C:/a"), new URI("file:c:/a"))); assertTrue("1.1", URIUtil.sameURI(new URI("file:/C:/a"), new URI("file:/c:/a"))); diff --git a/bundles/org.eclipse.equinox.common/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.common/META-INF/MANIFEST.MF index 47c4a0c9639..77de180a278 100644 --- a/bundles/org.eclipse.equinox.common/META-INF/MANIFEST.MF +++ b/bundles/org.eclipse.equinox.common/META-INF/MANIFEST.MF @@ -2,7 +2,7 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.equinox.common; singleton:=true -Bundle-Version: 3.19.200.qualifier +Bundle-Version: 3.20.0.qualifier Bundle-Localization: plugin Export-Package: org.eclipse.core.internal.boot;x-friends:="org.eclipse.core.resources,org.eclipse.pde.build", org.eclipse.core.internal.runtime;common=split;mandatory:=common; diff --git a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/DataArea.java b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/DataArea.java index 4619dedf2ac..dc73da68c62 100644 --- a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/DataArea.java +++ b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/DataArea.java @@ -65,12 +65,11 @@ protected synchronized void assertLocationInitialized() throws IllegalStateExcep // This will try to init url either from the specified location value or from // service default URL url = service.getURL(); - if (url == null) + if (url == null) { throw new IllegalStateException(CommonMessages.meta_instanceDataUnspecified); - // TODO assume the URL is a file: - // Use the new File technique to ensure that the resultant string is - // in the right format (e.g., leading / removed from /c:/foo etc) - location = IPath.fromOSString(new File(url.getFile()).toString()); + } + // Assume the URL is a file: + location = IPath.fromPath(URIUtil.toFilePath(url)); initializeLocation(); } catch (CoreException e) { throw new IllegalStateException(e.getMessage()); diff --git a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/PlatformURLConfigConnection.java b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/PlatformURLConfigConnection.java index c7af8a2605d..a1639d1b76e 100644 --- a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/PlatformURLConfigConnection.java +++ b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/internal/runtime/PlatformURLConfigConnection.java @@ -16,8 +16,10 @@ import java.io.*; import java.net.URL; import java.net.UnknownServiceException; +import java.nio.file.Files; import org.eclipse.core.internal.boot.PlatformURLConnection; import org.eclipse.core.internal.boot.PlatformURLHandler; +import org.eclipse.core.runtime.URIUtil; import org.eclipse.osgi.service.datalocation.Location; import org.eclipse.osgi.util.NLS; @@ -51,23 +53,21 @@ protected URL resolve() throws IOException { Location parentConfig = localConfig.getParentLocation(); // assume we will find the file locally URL localURL = new URL(localConfig.getURL(), path); - if (!FILE_PROTOCOL.equals(localURL.getProtocol()) || parentConfig == null) + if (!FILE_PROTOCOL.equals(localURL.getProtocol()) || parentConfig == null) { // we only support cascaded file: URLs return localURL; - File localFile = new File(localURL.getPath()); - if (localFile.exists()) + } + if (Files.exists(URIUtil.toFilePath(localURL))) { // file exists in local configuration return localURL; + } // try to find in the parent configuration URL parentURL = new URL(parentConfig.getURL(), path); - if (FILE_PROTOCOL.equals(parentURL.getProtocol())) { - // we only support cascaded file: URLs - File parentFile = new File(parentURL.getPath()); - if (parentFile.exists()) { - // parent has the location - parentConfiguration = true; - return parentURL; - } + // we only support cascaded file: URLs + if (FILE_PROTOCOL.equals(parentURL.getProtocol()) && Files.exists(URIUtil.toFilePath(parentURL))) { + // parent has the location + parentConfiguration = true; + return parentURL; } return localURL; } diff --git a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/URIUtil.java b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/URIUtil.java index 3645e1bee4d..ae461c674e4 100644 --- a/bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/URIUtil.java +++ b/bundles/org.eclipse.equinox.common/src/org/eclipse/core/runtime/URIUtil.java @@ -15,6 +15,7 @@ import java.io.File; import java.net.*; +import java.nio.file.Path; /** * A utility class for manipulating URIs. This class works around some of the @@ -312,11 +313,12 @@ public static URI toURI(URL url) throws URISyntaxException { // URL behaves differently across platforms so for file: URLs we parse from // string form if (SCHEME_FILE.equals(url.getProtocol())) { - String pathString = url.toExternalForm().substring(5); + String pathString = url.toExternalForm().substring(SCHEME_FILE.length() + 1); // ensure there is a leading slash to handle common malformed URLs such as // file:c:/tmp - if (pathString.indexOf('/') != 0) + if (!pathString.startsWith("/")) { //$NON-NLS-1$ pathString = '/' + pathString; + } return toURI(SCHEME_FILE, null, pathString, null); } try { @@ -328,6 +330,33 @@ public static URI toURI(URL url) throws URISyntaxException { } } + /** + * Returns the {@code Path} specified by the given {@code file} {@link URL}. + * + * @throws IllegalArgumentException if the specified URL does not use the + * {@code file} protocol + * + * @since 3.20 + */ + public static Path toFilePath(URL url) { + if (!SCHEME_FILE.equals(url.getProtocol())) { + throw new IllegalArgumentException("Not a 'file' url: " + url); //$NON-NLS-1$ + } + try { + return Path.of(url.toURI()); + } catch (URISyntaxException | IllegalArgumentException e) { + try { + return Path.of(toURI(url)); + } catch (URISyntaxException e1) { + String pathString = url.toExternalForm().substring(SCHEME_FILE.length() + 1); + if (pathString.length() > 1 && pathString.charAt(0) == '/' && pathString.charAt(1) != '/') { + pathString = pathString.substring(1); + } + return Path.of(pathString); + } + } + } + /** * An UNC-safe factory the the URI-ctor *