Code heavily inspired by Xerces-J code. This version is extremely simplified as it doesn't deal with non-ASCII characters for now. PR: 13679 git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@273552 13f79535-47bb-0310-9956-ffa450edef68master
@@ -0,0 +1,3 @@ | |||
<target name="test1"> | |||
<echo message="from included entity in 'with space'"/> | |||
</target> |
@@ -0,0 +1,9 @@ | |||
<?xml version="1.0"?> | |||
<!DOCTYPE project [ | |||
<!ENTITY include SYSTEM "file:include.inc"> | |||
]> | |||
<project name="include-test" basedir="." default="test1"> | |||
&include; | |||
</project> |
@@ -0,0 +1,9 @@ | |||
<?xml version="1.0"?> | |||
<!DOCTYPE project [ | |||
<!ENTITY include SYSTEM "include.inc"> | |||
]> | |||
<project name="include-test" basedir="." default="test1"> | |||
&include; | |||
</project> |
@@ -0,0 +1,6 @@ | |||
<?xml version="1.0"?> | |||
<project name="include-test" basedir="." default="test1"> | |||
<target name="test1"> | |||
<echo message="from simple buildfile in 'with space'"/> | |||
</target> | |||
</project> |
@@ -71,6 +71,7 @@ import org.apache.tools.ant.Task; | |||
import org.apache.tools.ant.TaskAdapter; | |||
import org.apache.tools.ant.TaskContainer; | |||
import org.apache.tools.ant.UnknownElement; | |||
import org.apache.tools.ant.util.FileUtils; | |||
import org.apache.tools.ant.util.JAXPUtils; | |||
import org.xml.sax.AttributeList; | |||
import org.xml.sax.DocumentHandler; | |||
@@ -115,6 +116,10 @@ public class ProjectHelperImpl extends ProjectHelper { | |||
* been placed outside of targets.</p> | |||
*/ | |||
private Target implicitTarget = new Target(); | |||
/** | |||
* helper for path -> URI and URI -> path conversions. | |||
*/ | |||
private static FileUtils fu = FileUtils.newFileUtils(); | |||
public ProjectHelperImpl() { | |||
implicitTarget.setName(""); | |||
@@ -148,11 +153,7 @@ public class ProjectHelperImpl extends ProjectHelper { | |||
} | |||
String uri = "file:" + buildFile.getAbsolutePath().replace('\\', '/'); | |||
for (int index = uri.indexOf('#'); index != -1; index = uri.indexOf('#')) { | |||
uri = uri.substring(0, index) + "%23" + uri.substring(index + 1); | |||
} | |||
String uri = fu.toURI(buildFile.getAbsolutePath()); | |||
inputStream = new FileInputStream(buildFile); | |||
inputSource = new InputSource(inputStream); | |||
inputSource.setSystemId(uri); | |||
@@ -329,32 +330,15 @@ public class ProjectHelperImpl extends ProjectHelper { | |||
helperImpl.project.log("resolving systemId: " + systemId, Project.MSG_VERBOSE); | |||
if (systemId.startsWith("file:")) { | |||
String path = systemId.substring(5); | |||
int index = path.indexOf("file:"); | |||
// we only have to handle these for backward compatibility | |||
// since they are in the FAQ. | |||
while (index != -1) { | |||
path = path.substring(0, index) + path.substring(index + 5); | |||
index = path.indexOf("file:"); | |||
} | |||
String entitySystemId = path; | |||
index = path.indexOf("%23"); | |||
// convert these to # | |||
while (index != -1) { | |||
path = path.substring(0, index) + "#" + path.substring(index + 3); | |||
index = path.indexOf("%23"); | |||
} | |||
String path = fu.fromURI(systemId); | |||
File file = new File(path); | |||
if (!file.isAbsolute()) { | |||
file = new File(helperImpl.buildFileParent, path); | |||
file = fu.resolveFile(helperImpl.buildFileParent, path); | |||
} | |||
try { | |||
InputSource inputSource = new InputSource(new FileInputStream(file)); | |||
inputSource.setSystemId("file:" + entitySystemId); | |||
inputSource.setSystemId(fu.toURI(file.getAbsolutePath())); | |||
return inputSource; | |||
} catch (FileNotFoundException fne) { | |||
helperImpl.project.log(file.getAbsolutePath() + " could not be found", | |||
@@ -70,7 +70,9 @@ import java.io.Reader; | |||
import java.lang.reflect.Method; | |||
import java.net.MalformedURLException; | |||
import java.net.URL; | |||
import java.text.CharacterIterator; | |||
import java.text.DecimalFormat; | |||
import java.text.StringCharacterIterator; | |||
import java.util.Random; | |||
import java.util.Stack; | |||
import java.util.StringTokenizer; | |||
@@ -103,6 +105,34 @@ public class FileUtils { | |||
private boolean onNetWare = Os.isFamily("netware"); | |||
// for toURI | |||
private static boolean[] isSpecial = new boolean[256]; | |||
private static char[] escapedChar1 = new char[256]; | |||
private static char[] escapedChar2 = new char[256]; | |||
// stolen from FilePathToURI of the Xerces-J team | |||
static { | |||
for (int i = 0; i <= 0x20; i++) { | |||
isSpecial[i] = true; | |||
escapedChar1[i] = Character.forDigit(i >> 4, 16); | |||
escapedChar2[i] = Character.forDigit(i & 0xf, 16); | |||
} | |||
isSpecial[0x7f] = true; | |||
escapedChar1[0x7f] = '7'; | |||
escapedChar2[0x7f] = 'F'; | |||
char[] escChs = {'<', '>', '#', '%', '"', '{', '}', | |||
'|', '\\', '^', '~', '[', ']', '`'}; | |||
int len = escChs.length; | |||
char ch; | |||
for (int i = 0; i < len; i++) { | |||
ch = escChs[i]; | |||
isSpecial[ch] = true; | |||
escapedChar1[ch] = Character.forDigit(ch >> 4, 16); | |||
escapedChar2[ch] = Character.forDigit(ch & 0xf, 16); | |||
} | |||
} | |||
/** | |||
* Factory method. | |||
*/ | |||
@@ -124,14 +154,11 @@ public class FileUtils { | |||
* formed. | |||
*/ | |||
public URL getFileURL(File file) throws MalformedURLException { | |||
String uri = "file:" + file.getAbsolutePath().replace('\\', '/'); | |||
for (int i = uri.indexOf('#'); i != -1; i = uri.indexOf('#')) { | |||
uri = uri.substring(0, i) + "%23" + uri.substring(i + 1); | |||
} | |||
String path = file.getAbsolutePath(); | |||
if (file.isDirectory()) { | |||
uri += "/"; | |||
path += "/"; | |||
} | |||
return new URL(uri); | |||
return new URL(toURI(path)); | |||
} | |||
/** | |||
@@ -168,7 +195,7 @@ public class FileUtils { | |||
overwrite, false); | |||
} | |||
/** | |||
/** | |||
* Convienence method to copy a file from a source to a | |||
* destination specifying if token filtering must be used, if | |||
* source files may overwrite newer destination files and the | |||
@@ -342,12 +369,12 @@ public class FileUtils { | |||
} else { | |||
in = | |||
new BufferedReader(new InputStreamReader( | |||
new FileInputStream(sourceFile), | |||
encoding)); | |||
new FileInputStream(sourceFile), | |||
encoding)); | |||
out = | |||
new BufferedWriter(new OutputStreamWriter( | |||
new FileOutputStream(destFile), | |||
encoding)); | |||
new FileOutputStream(destFile), | |||
encoding)); | |||
} | |||
if (filterChainsAvailable) { | |||
@@ -555,8 +582,8 @@ public class FileUtils { | |||
if (!onNetWare) { | |||
if (!path.startsWith(File.separator) && | |||
!(path.length() >= 2 && | |||
Character.isLetter(path.charAt(0)) && | |||
colon == 1)) { | |||
Character.isLetter(path.charAt(0)) && | |||
colon == 1)) { | |||
String msg = path + " is not an absolute path"; | |||
throw new BuildException(msg); | |||
} | |||
@@ -780,7 +807,7 @@ public class FileUtils { | |||
public static final String readFully(Reader rdr, int bufferSize) throws IOException { | |||
if (bufferSize <= 0) { | |||
throw new IllegalArgumentException("Buffer size must be greater " | |||
+ "than 0"); | |||
+ "than 0"); | |||
} | |||
final char[] buffer = new char[bufferSize]; | |||
int bufferLength = 0; | |||
@@ -791,7 +818,7 @@ public class FileUtils { | |||
if (bufferLength != -1) { | |||
if (textBuffer == null) { | |||
textBuffer = new StringBuffer( | |||
new String(buffer, 0, bufferLength)); | |||
new String(buffer, 0, bufferLength)); | |||
} else { | |||
textBuffer.append(new String(buffer, 0, bufferLength)); | |||
} | |||
@@ -875,5 +902,92 @@ public class FileUtils { | |||
return p; | |||
} | |||
} | |||
/** | |||
* Constructs a <code>file:</code> URI that represents the | |||
* external form of the given pathname. | |||
* | |||
* <p>Will be an absolute URI if the given path is absolute.</p> | |||
* | |||
* <p>This code doesn't handle non-ASCII characters properly.</p> | |||
* | |||
* @since Ant 1.6 | |||
*/ | |||
public String toURI(String path) { | |||
StringBuffer sb = new StringBuffer("file:"); | |||
// catch exception if normalize thinks this is not an absolute path | |||
try { | |||
path = normalize(path).getAbsolutePath(); | |||
sb.append("//"); | |||
} catch (BuildException e) { | |||
// relative path | |||
} | |||
path = path.replace('\\', '/'); | |||
CharacterIterator iter = new StringCharacterIterator(path); | |||
for (char c = iter.first(); c != CharacterIterator.DONE; | |||
c = iter.next()) { | |||
if (isSpecial[c]) { | |||
sb.append('%'); | |||
sb.append(escapedChar1[c]); | |||
sb.append(escapedChar2[c]); | |||
} else { | |||
sb.append(c); | |||
} | |||
} | |||
return sb.toString(); | |||
} | |||
/** | |||
* Constructs a file path from a <code>file:</code> URI. | |||
* | |||
* <p>Will be an absolute path if the given URI is absolute.</p> | |||
* | |||
* <p>Swallows '%' that are not followed by two characters, | |||
* doesn't deal with non-ASCII characters.</p> | |||
* | |||
* @since Ant 1.6 | |||
*/ | |||
public String fromURI(String uri) { | |||
if (!uri.startsWith("file:")) { | |||
throw new IllegalArgumentException("Can only handle file: URIs"); | |||
} | |||
if (uri.startsWith("file://")) { | |||
uri = uri.substring(7); | |||
} else { | |||
uri = uri.substring(5); | |||
} | |||
uri = uri.replace('/', File.separatorChar); | |||
StringBuffer sb = new StringBuffer(); | |||
CharacterIterator iter = new StringCharacterIterator(uri); | |||
for (char c = iter.first(); c != CharacterIterator.DONE; | |||
c = iter.next()) { | |||
if (c == '%') { | |||
char c1 = iter.next(); | |||
if (c1 != CharacterIterator.DONE) { | |||
int i1 = Character.digit(c1, 16); | |||
char c2 = iter.next(); | |||
if (c2 != CharacterIterator.DONE) { | |||
int i2 = Character.digit(c2, 16); | |||
sb.append((char) ((i1 << 4) + i2)); | |||
} | |||
} | |||
} else { | |||
sb.append(c); | |||
} | |||
} | |||
String path = sb.toString(); | |||
// catch exception if normalize thinks this is not an absolute path | |||
try { | |||
path = normalize(path).getAbsolutePath(); | |||
} catch (BuildException e) { | |||
// relative path | |||
} | |||
return path; | |||
} | |||
} | |||
@@ -145,4 +145,19 @@ public class IncludeTest extends BuildFileTest { | |||
} | |||
} | |||
public void testWithSpaceInclude() { | |||
configureProject("src/etc/testcases/core/include/with space/include.xml"); | |||
expectLog("test1", "from included entity in 'with space'"); | |||
} | |||
public void testWithSpaceSimple() { | |||
configureProject("src/etc/testcases/core/include/with space/simple.xml"); | |||
expectLog("test1", "from simple buildfile in 'with space'"); | |||
} | |||
public void testWithSpaceRelative() { | |||
configureProject("src/etc/testcases/core/include/with space/relative.xml"); | |||
expectLog("test1", "from included entity in 'with space'"); | |||
} | |||
} |
@@ -408,6 +408,37 @@ public class FileUtilsTest extends TestCase { | |||
fu.removeLeadingPath(new File("/foo"), new File("/foobar"))); | |||
} | |||
/** | |||
* test toUri | |||
*/ | |||
public void testToURI() { | |||
if (Os.isFamily("windows")) { | |||
assertEquals("file://C:/foo", fu.toURI("c:\\foo")); | |||
} | |||
assertEquals("file:///foo", fu.toURI("/foo")); | |||
assertEquals("file:./foo", fu.toURI("./foo")); | |||
assertEquals("file:///foo", fu.toURI("\\foo")); | |||
assertEquals("file:./foo", fu.toURI(".\\foo")); | |||
assertEquals("file:///foo%20bar", fu.toURI("/foo bar")); | |||
assertEquals("file:///foo%20bar", fu.toURI("\\foo bar")); | |||
assertEquals("file:///foo%23bar", fu.toURI("/foo#bar")); | |||
assertEquals("file:///foo%23bar", fu.toURI("\\foo#bar")); | |||
} | |||
/** | |||
* test fromUri | |||
*/ | |||
public void testFromURI() { | |||
if (Os.isFamily("windows")) { | |||
assertEquals("C:\\foo", fu.fromURI("file://c:/foo")); | |||
} | |||
assertEquals(localize("/foo"), fu.fromURI("file:///foo")); | |||
assertEquals("." + File.separator + "foo", | |||
fu.fromURI("file:./foo")); | |||
assertEquals(localize("/foo bar"), fu.fromURI("file:///foo%20bar")); | |||
assertEquals(localize("/foo#bar"), fu.fromURI("file:///foo%23bar")); | |||
} | |||
/** | |||
* adapt file separators to local conventions | |||
*/ | |||