Index: src/main/org/apache/tools/ant/AntClassLoader.java =================================================================== RCS file: /home/cvspublic/ant/src/main/org/apache/tools/ant/AntClassLoader.java,v --- src/main/org/apache/tools/ant/AntClassLoader.java 9 Sep 2003 16:52:03 -0000 1.76 +++ src/main/org/apache/tools/ant/AntClassLoader.java 23 Oct 2003 19:26:53 -0000 @@ -69,6 +69,7 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.JavaEnvUtils; import org.apache.tools.ant.util.LoaderUtils; @@ -929,8 +930,9 @@ if (resource.exists()) { try { - return new URL("file:" + resource.toString()); + return new URL(FileUtils.newFileUtils().toURI(resource.getAbsolutePath())); } catch (MalformedURLException ex) { + ex.printStackTrace(); // not expected return null; } } @@ -944,9 +946,10 @@ ZipEntry entry = zipFile.getEntry(resourceName); if (entry != null) { try { - return new URL("jar:file:" + file.toString() + return new URL("jar:" + FileUtils.newFileUtils().toURI(file.getAbsolutePath()) + "!/" + entry); } catch (MalformedURLException ex) { + ex.printStackTrace(); // not expected return null; } } Index: src/main/org/apache/tools/ant/launch/Locator.java =================================================================== RCS file: /home/cvspublic/ant/src/main/org/apache/tools/ant/launch/Locator.java,v --- src/main/org/apache/tools/ant/launch/Locator.java 12 Sep 2003 20:56:46 -0000 1.6 +++ src/main/org/apache/tools/ant/launch/Locator.java 23 Oct 2003 19:26:53 -0000 @@ -124,16 +124,53 @@ /** * Constructs a file path from a file: URI. * - *

Will be an absolute path if the given URI is absolute.

+ *

Will be an absolute path if the given URI is absolute (required on Java 1.4).

* - *

Swallows '%' that are not followed by two characters, + *

Prior to Java 1.4, swallows '%' that are not followed by two characters, * doesn't deal with non-ASCII characters.

* * @param uri the URI designating a file in the local filesystem. * @return the local file system path for the file. + * @throws IllegalArgumentException if the URI is malformed or not a legal file: URL * @since Ant 1.6 */ public static String fromURI(String uri) { + + // #8031: first try Java 1.4. + Class uriClazz = null; + try { + uriClazz = Class.forName("java.net.URI"); + } catch (ClassNotFoundException cnfe) { + // Fine, Java 1.3 or earlier, do it by hand. + } + // Also check for properly formed URIs. Ant formerly recommended using + // nonsense URIs such as "file:./foo.xml" in XML includes. You shouldn't + // do that (just "foo.xml" is correct) but for compatibility we special-case + // things when the path is not absolute, and fall back to the old parsing behavior. + if (uriClazz != null && uri.startsWith("file:/")) { + try { + java.lang.reflect.Method createMethod = uriClazz.getMethod("create", new Class[] {String.class}); + Object uriObj = createMethod.invoke(null, new Object[] {uri}); + java.lang.reflect.Constructor fileConst = File.class.getConstructor(new Class[] {uriClazz}); + File f = (File)fileConst.newInstance(new Object[] {uriObj}); + return f.getAbsolutePath(); + } catch (java.lang.reflect.InvocationTargetException e) { + Throwable e2 = e.getTargetException(); + if (e2 instanceof IllegalArgumentException) { + // Bad URI, pass this on. + throw (IllegalArgumentException)e2; + } else { + // Unexpected target exception? Should not happen. + e2.printStackTrace(); + } + } catch (Exception e) { + // Reflection problems? Should not happen, debug. + e.printStackTrace(); + } + } + + // Fallback method for Java 1.3 or earlier. + if (!uri.startsWith("file:")) { throw new IllegalArgumentException("Can only handle file: URIs"); } Index: src/main/org/apache/tools/ant/loader/AntClassLoader2.java =================================================================== RCS file: /home/cvspublic/ant/src/main/org/apache/tools/ant/loader/AntClassLoader2.java,v --- src/main/org/apache/tools/ant/loader/AntClassLoader2.java 17 Jul 2003 10:36:27 -0000 1.7 +++ src/main/org/apache/tools/ant/loader/AntClassLoader2.java 23 Oct 2003 19:26:53 -0000 @@ -243,7 +243,7 @@ if (sealedString != null && sealedString.equalsIgnoreCase("true")) { try { - sealBase = new URL("file:" + container.getPath()); + sealBase = new URL(FileUtils.newFileUtils().toURI(container.getAbsolutePath())); } catch (MalformedURLException e) { // ignore } Index: src/main/org/apache/tools/ant/taskdefs/XSLTLiaison.java =================================================================== RCS file: /home/cvspublic/ant/src/main/org/apache/tools/ant/taskdefs/XSLTLiaison.java,v --- src/main/org/apache/tools/ant/taskdefs/XSLTLiaison.java 6 Jul 2003 09:03:17 -0000 1.15 +++ src/main/org/apache/tools/ant/taskdefs/XSLTLiaison.java 23 Oct 2003 19:26:53 -0000 @@ -1,7 +1,7 @@ /* * The Apache Software License, Version 1.1 * - * Copyright (c) 2000-2002 The Apache Software Foundation. All rights + * Copyright (c) 2000-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -65,16 +65,6 @@ * @since Ant 1.1 */ public interface XSLTLiaison { - - /** - * the file protocol prefix for systemid. - * This file protocol must be appended to an absolute path. - * Typically: FILE_PROTOCOL_PREFIX + file.getAbsolutePath() - * Note that on Windows, an extra '/' must be appended to the - * protocol prefix so that there is always 3 consecutive slashes. - * @since Ant 1.4 - */ - String FILE_PROTOCOL_PREFIX = "file://"; /** * set the stylesheet to use for the transformation. Index: src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java =================================================================== RCS file: /home/cvspublic/ant/src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java,v --- src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java 23 Oct 2003 08:43:22 -0000 1.31 +++ src/main/org/apache/tools/ant/taskdefs/optional/TraXLiaison.java 23 Oct 2003 19:26:53 -0000 @@ -84,6 +84,7 @@ import org.apache.tools.ant.taskdefs.XSLTLogger; import org.apache.tools.ant.taskdefs.XSLTLoggerAware; import org.apache.tools.ant.types.XMLCatalog; +import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.JAXPUtils; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; @@ -401,8 +402,8 @@ String systemid = locator.getSystemId(); if (systemid != null) { String url = systemid; - if (url.startsWith("file:///")) { - url = url.substring(8); + if (url.startsWith("file:")) { + url = FileUtils.newFileUtils().fromURI(url); } msg.append(url); } else { Index: src/main/org/apache/tools/ant/taskdefs/optional/depend/Depend.java =================================================================== RCS file: /home/cvspublic/ant/src/main/org/apache/tools/ant/taskdefs/optional/depend/Depend.java,v --- src/main/org/apache/tools/ant/taskdefs/optional/depend/Depend.java 17 Sep 2003 20:11:44 -0000 1.38 +++ src/main/org/apache/tools/ant/taskdefs/optional/depend/Depend.java 23 Oct 2003 19:26:53 -0000 @@ -70,6 +70,7 @@ import org.apache.tools.ant.taskdefs.MatchingTask; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; +import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.depend.DependencyAnalyzer; /** @@ -417,14 +418,15 @@ if (classURL != null) { if (classURL.getProtocol().equals("jar")) { String jarFilePath = classURL.getFile(); + int classMarker = jarFilePath.indexOf('!'); + jarFilePath = jarFilePath.substring(0, classMarker); if (jarFilePath.startsWith("file:")) { - int classMarker = jarFilePath.indexOf('!'); - jarFilePath = jarFilePath.substring(5, classMarker); + classpathFileObject = new File(FileUtils.newFileUtils().fromURI(jarFilePath)); + } else { + throw new IOException("Bizarre nested path in jar: protocol: " + jarFilePath); } - classpathFileObject = new File(jarFilePath); } else if (classURL.getProtocol().equals("file")) { - String classFilePath = classURL.getFile(); - classpathFileObject = new File(classFilePath); + classpathFileObject = new File(FileUtils.newFileUtils().fromURI(classURL.toExternalForm())); } log("Class " + className + " depends on " + classpathFileObject Index: src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLResultAggregator.java =================================================================== RCS file: /home/cvspublic/ant/src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLResultAggregator.java,v --- src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLResultAggregator.java 13 Aug 2003 15:02:28 -0000 1.25 +++ src/main/org/apache/tools/ant/taskdefs/optional/junit/XMLResultAggregator.java 23 Oct 2003 19:26:53 -0000 @@ -70,6 +70,7 @@ import org.apache.tools.ant.Task; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.util.DOMElementWriter; +import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.StringUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -271,7 +272,7 @@ // will investigate later. It does not use the given directory but // the vm dir instead ? Works fine with crimson. Document testsuiteDoc - = builder.parse("file:///" + files[i].getAbsolutePath()); + = builder.parse(FileUtils.newFileUtils().toURI(files[i].getAbsolutePath())); Element elem = testsuiteDoc.getDocumentElement(); // make sure that this is REALLY a testsuite. if (TESTSUITE.equals(elem.getNodeName())) { Index: src/main/org/apache/tools/ant/taskdefs/optional/sitraka/CovReport.java =================================================================== RCS file: /home/cvspublic/ant/src/main/org/apache/tools/ant/taskdefs/optional/sitraka/CovReport.java,v --- src/main/org/apache/tools/ant/taskdefs/optional/sitraka/CovReport.java 25 Jul 2003 12:14:44 -0000 1.19 +++ src/main/org/apache/tools/ant/taskdefs/optional/sitraka/CovReport.java 23 Oct 2003 19:26:53 -0000 @@ -395,7 +395,7 @@ transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); Source src = new DOMSource(doc); - Result res = new StreamResult("file:///" + tofile.toString()); + Result res = new StreamResult(tofile); transformer.transform(src, res); } catch (Exception e) { throw new BuildException("Error while performing enhanced XML " Index: src/main/org/apache/tools/ant/taskdefs/optional/sitraka/XMLReport.java =================================================================== RCS file: /home/cvspublic/ant/src/main/org/apache/tools/ant/taskdefs/optional/sitraka/XMLReport.java,v --- src/main/org/apache/tools/ant/taskdefs/optional/sitraka/XMLReport.java 14 Aug 2003 07:04:41 -0000 1.16 +++ src/main/org/apache/tools/ant/taskdefs/optional/sitraka/XMLReport.java 23 Oct 2003 19:26:53 -0000 @@ -67,6 +67,7 @@ import org.apache.tools.ant.taskdefs.optional.sitraka.bytecode.ClassPathLoader; import org.apache.tools.ant.taskdefs.optional.sitraka.bytecode.MethodInfo; import org.apache.tools.ant.taskdefs.optional.sitraka.bytecode.Utils; +import org.apache.tools.ant.util.FileUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -213,8 +214,10 @@ DocumentBuilder dbuilder = newBuilder(); InputSource is = new InputSource(new FileInputStream(file)); if (jprobeHome != null) { + // XXX this is an abuse of setSystemId... + // probably wanted to make an EntityResolver instead! File dtdDir = new File(jprobeHome, "dtd"); - is.setSystemId("file:///" + dtdDir.getAbsolutePath() + "/"); + is.setSystemId(FileUtils.newFileUtils().toURI(dtdDir.getAbsolutePath()) + "/"); } report = dbuilder.parse(is); report.normalize(); Index: src/main/org/apache/tools/ant/util/FileUtils.java =================================================================== RCS file: /home/cvspublic/ant/src/main/org/apache/tools/ant/util/FileUtils.java,v --- src/main/org/apache/tools/ant/util/FileUtils.java 25 Sep 2003 12:36:19 -0000 1.57 +++ src/main/org/apache/tools/ant/util/FileUtils.java 23 Oct 2003 19:26:53 -0000 @@ -1268,15 +1268,45 @@ * Constructs a file: URI that represents the * external form of the given pathname. * - *

Will be an absolute URI if the given path is absolute.

+ *

Will be an absolute URI. If the incoming path is not + * absolute, it will be absolutized relative to Java's + * current directory, as by {@link File#getAbsolutePath}.

* - *

This code doesn't handle non-ASCII characters properly.

+ *

This code doesn't handle non-ASCII characters properly prior to Java 1.4.

* * @param path the path in the local file system * @return the URI version of the local path. * @since Ant 1.6 */ public String toURI(String path) { + + // #8031: first try Java 1.4. + Class uriClazz = null; + try { + uriClazz = Class.forName("java.net.URI"); + } catch (ClassNotFoundException e) { + // OK, Java 1.3. + } + if (uriClazz != null) { + try { + File f = new File(path).getAbsoluteFile(); + java.lang.reflect.Method toURIMethod = File.class.getMethod("toURI", new Class[0]); + Object uriObj = toURIMethod.invoke(f, null); + return uriObj.toString(); + } catch (Exception e) { + // Reflection problems? Should not happen, debug. + e.printStackTrace(); + } + } + + // Fallback for Java 1.3. + + File f = new File(path); + if (!f.isAbsolute()) { + f = f.getAbsoluteFile(); + path = f.getAbsolutePath(); + } + boolean isDir = (new File(path)).isDirectory(); StringBuffer sb = new StringBuffer("file:"); @@ -1291,7 +1321,7 @@ } } catch (BuildException e) { - // relative path + e.printStackTrace(); // relative path - should not happen } path = path.replace('\\', '/'); Index: src/testcases/org/apache/tools/ant/util/FileUtilsTest.java =================================================================== RCS file: /home/cvspublic/ant/src/testcases/org/apache/tools/ant/util/FileUtilsTest.java,v --- src/testcases/org/apache/tools/ant/util/FileUtilsTest.java 22 Jul 2003 14:52:45 -0000 1.22 +++ src/testcases/org/apache/tools/ant/util/FileUtilsTest.java 23 Oct 2003 19:26:53 -0000 @@ -436,6 +436,8 @@ * test toUri */ public void testToURI() { + // Tricky because the syntax of a file: URI is platform-dependent and + // not fully specified by Java. String dosRoot = null; if (Os.isFamily("dos")) { dosRoot = System.getProperty("user.dir").charAt(0) + ":/"; @@ -445,19 +447,37 @@ dosRoot = ""; } if (Os.isFamily("dos")) { - assertEquals("file:///C:/foo", fu.toURI("c:\\foo")); + assertEquals("file:/C:/foo", removeExtraneousAuthority(fu.toURI("c:\\foo"))); } if (Os.isFamily("netware")) { - assertEquals("file:///SYS:/foo", fu.toURI("sys:\\foo")); + assertEquals("file:/SYS:/foo", removeExtraneousAuthority(fu.toURI("sys:\\foo"))); + } + if (File.pathSeparatorChar == '/') { + assertEquals("file:/foo", removeExtraneousAuthority(fu.toURI("/foo"))); + assertTrue("file: URIs must name absolute paths", fu.toURI("./foo").startsWith("file:/")); + assertTrue(fu.toURI("./foo").endsWith("/foo")); + assertEquals("file:/" + dosRoot + "foo%20bar", removeExtraneousAuthority(fu.toURI("/foo bar"))); + assertEquals("file:/" + dosRoot + "foo%23bar", removeExtraneousAuthority(fu.toURI("/foo#bar"))); + } else if (File.pathSeparatorChar == '\\') { + assertEquals("file:/" + dosRoot + "foo", removeExtraneousAuthority(fu.toURI("\\foo"))); + assertTrue("file: URIs must name absolute paths", fu.toURI(".\\foo").startsWith("file:/")); + assertTrue(fu.toURI(".\\foo").endsWith("/foo")); + assertEquals("file:/" + dosRoot + "foo%20bar", removeExtraneousAuthority(fu.toURI("\\foo bar"))); + assertEquals("file:/" + dosRoot + "foo%23bar", removeExtraneousAuthority(fu.toURI("\\foo#bar"))); + } + } + + /** + * Authority field is unnecessary, but harmless, in file: URIs. + * Java 1.4 does not produce it when using File.toURI. + */ + private static String removeExtraneousAuthority(String uri) { + String prefix = "file:///"; + if (uri.startsWith(prefix)) { + return "file:/" + uri.substring(prefix.length()); + } else { + return uri; } - assertEquals("file:///" + dosRoot + "foo", fu.toURI("/foo")); - assertEquals("file:./foo", fu.toURI("./foo")); - assertEquals("file:///" + dosRoot + "foo", fu.toURI("\\foo")); - assertEquals("file:./foo", fu.toURI(".\\foo")); - assertEquals("file:///" + dosRoot + "foo%20bar", fu.toURI("/foo bar")); - assertEquals("file:///" + dosRoot + "foo%20bar", fu.toURI("\\foo bar")); - assertEquals("file:///" + dosRoot + "foo%23bar", fu.toURI("/foo#bar")); - assertEquals("file:///" + dosRoot + "foo%23bar", fu.toURI("\\foo#bar")); } /** @@ -471,8 +491,10 @@ assertEqualsIgnoreDriveCase("C:\\foo", fu.fromURI("file:///c:/foo")); } assertEqualsIgnoreDriveCase(localize("/foo"), fu.fromURI("file:///foo")); + /* Illegal URI. assertEquals("." + File.separator + "foo", fu.fromURI("file:./foo")); + */ assertEqualsIgnoreDriveCase(localize("/foo bar"), fu.fromURI("file:///foo%20bar")); assertEqualsIgnoreDriveCase(localize("/foo#bar"), fu.fromURI("file:///foo%23bar")); } Index: src/testcases/org/apache/tools/ant/util/JAXPUtilsTest.java =================================================================== RCS file: /home/cvspublic/ant/src/testcases/org/apache/tools/ant/util/JAXPUtilsTest.java,v --- src/testcases/org/apache/tools/ant/util/JAXPUtilsTest.java 10 Feb 2003 14:14:58 -0000 1.3 +++ src/testcases/org/apache/tools/ant/util/JAXPUtilsTest.java 23 Oct 2003 19:26:53 -0000 @@ -1,7 +1,7 @@ /* * The Apache Software License, Version 1.1 * - * Copyright (c) 2002 The Apache Software Foundation. All rights + * Copyright (c) 2002-2003 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -74,7 +74,7 @@ file = new File("/user/local/bin"); } String systemid = JAXPUtils.getSystemId(file); - assertTrue("SystemIDs should start by file:///", systemid.startsWith("file:///")); + assertTrue("SystemIDs should start by file:/", systemid.startsWith("file:/")); assertTrue("SystemIDs should not start with file:////", !systemid.startsWith("file:////")); } } Index: xdocs/faq.xml =================================================================== RCS file: /home/cvspublic/ant/xdocs/faq.xml,v --- xdocs/faq.xml 13 Oct 2003 15:29:52 -0000 1.43 +++ xdocs/faq.xml 23 Oct 2003 19:26:53 -0000 @@ -836,7 +836,7 @@ + ]> @@ -855,11 +855,15 @@

will literally include the contents of common.xml where you've placed the &common; entity.

+

(The filename common.xml in this example is resolved + relative to the containing XML file by the XML parser. You may also use + an absolute file: protocol URI.)

+

In combination with a DTD, this would look like this:

+ ]> ]]>