Browse Source

Don't stop with encoding # when creating URIs for the XML parser.

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-ffa450edef68
master
Stefan Bodewig 22 years ago
parent
commit
6b5c48061a
8 changed files with 211 additions and 40 deletions
  1. +3
    -0
      src/etc/testcases/core/include/with space/include.inc
  2. +9
    -0
      src/etc/testcases/core/include/with space/include.xml
  3. +9
    -0
      src/etc/testcases/core/include/with space/relative.xml
  4. +6
    -0
      src/etc/testcases/core/include/with space/simple.xml
  5. +9
    -25
      src/main/org/apache/tools/ant/helper/ProjectHelperImpl.java
  6. +129
    -15
      src/main/org/apache/tools/ant/util/FileUtils.java
  7. +15
    -0
      src/testcases/org/apache/tools/ant/IncludeTest.java
  8. +31
    -0
      src/testcases/org/apache/tools/ant/util/FileUtilsTest.java

+ 3
- 0
src/etc/testcases/core/include/with space/include.inc View File

@@ -0,0 +1,3 @@
<target name="test1">
<echo message="from included entity in &apos;with space&apos;"/>
</target>

+ 9
- 0
src/etc/testcases/core/include/with space/include.xml View File

@@ -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>

+ 9
- 0
src/etc/testcases/core/include/with space/relative.xml View File

@@ -0,0 +1,9 @@
<?xml version="1.0"?>

<!DOCTYPE project [
<!ENTITY include SYSTEM "include.inc">
]>

<project name="include-test" basedir="." default="test1">
&include;
</project>

+ 6
- 0
src/etc/testcases/core/include/with space/simple.xml View File

@@ -0,0 +1,6 @@
<?xml version="1.0"?>
<project name="include-test" basedir="." default="test1">
<target name="test1">
<echo message="from simple buildfile in &apos;with space&apos;"/>
</target>
</project>

+ 9
- 25
src/main/org/apache/tools/ant/helper/ProjectHelperImpl.java View File

@@ -71,6 +71,7 @@ import org.apache.tools.ant.Task;
import org.apache.tools.ant.TaskAdapter; import org.apache.tools.ant.TaskAdapter;
import org.apache.tools.ant.TaskContainer; import org.apache.tools.ant.TaskContainer;
import org.apache.tools.ant.UnknownElement; import org.apache.tools.ant.UnknownElement;
import org.apache.tools.ant.util.FileUtils;
import org.apache.tools.ant.util.JAXPUtils; import org.apache.tools.ant.util.JAXPUtils;
import org.xml.sax.AttributeList; import org.xml.sax.AttributeList;
import org.xml.sax.DocumentHandler; import org.xml.sax.DocumentHandler;
@@ -115,6 +116,10 @@ public class ProjectHelperImpl extends ProjectHelper {
* been placed outside of targets.</p> * been placed outside of targets.</p>
*/ */
private Target implicitTarget = new Target(); private Target implicitTarget = new Target();
/**
* helper for path -> URI and URI -> path conversions.
*/
private static FileUtils fu = FileUtils.newFileUtils();


public ProjectHelperImpl() { public ProjectHelperImpl() {
implicitTarget.setName(""); 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); inputStream = new FileInputStream(buildFile);
inputSource = new InputSource(inputStream); inputSource = new InputSource(inputStream);
inputSource.setSystemId(uri); inputSource.setSystemId(uri);
@@ -329,32 +330,15 @@ public class ProjectHelperImpl extends ProjectHelper {
helperImpl.project.log("resolving systemId: " + systemId, Project.MSG_VERBOSE); helperImpl.project.log("resolving systemId: " + systemId, Project.MSG_VERBOSE);


if (systemId.startsWith("file:")) { 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); File file = new File(path);
if (!file.isAbsolute()) { if (!file.isAbsolute()) {
file = new File(helperImpl.buildFileParent, path);
file = fu.resolveFile(helperImpl.buildFileParent, path);
} }

try { try {
InputSource inputSource = new InputSource(new FileInputStream(file)); InputSource inputSource = new InputSource(new FileInputStream(file));
inputSource.setSystemId("file:" + entitySystemId);
inputSource.setSystemId(fu.toURI(file.getAbsolutePath()));
return inputSource; return inputSource;
} catch (FileNotFoundException fne) { } catch (FileNotFoundException fne) {
helperImpl.project.log(file.getAbsolutePath() + " could not be found", helperImpl.project.log(file.getAbsolutePath() + " could not be found",


+ 129
- 15
src/main/org/apache/tools/ant/util/FileUtils.java View File

@@ -70,7 +70,9 @@ import java.io.Reader;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.text.CharacterIterator;
import java.text.DecimalFormat; import java.text.DecimalFormat;
import java.text.StringCharacterIterator;
import java.util.Random; import java.util.Random;
import java.util.Stack; import java.util.Stack;
import java.util.StringTokenizer; import java.util.StringTokenizer;
@@ -103,6 +105,34 @@ public class FileUtils {


private boolean onNetWare = Os.isFamily("netware"); 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. * Factory method.
*/ */
@@ -124,14 +154,11 @@ public class FileUtils {
* formed. * formed.
*/ */
public URL getFileURL(File file) throws MalformedURLException { 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()) { if (file.isDirectory()) {
uri += "/";
path += "/";
} }
return new URL(uri);
return new URL(toURI(path));
} }


/** /**
@@ -168,7 +195,7 @@ public class FileUtils {
overwrite, false); overwrite, false);
} }


/**
/**
* Convienence method to copy a file from a source to a * Convienence method to copy a file from a source to a
* destination specifying if token filtering must be used, if * destination specifying if token filtering must be used, if
* source files may overwrite newer destination files and the * source files may overwrite newer destination files and the
@@ -342,12 +369,12 @@ public class FileUtils {
} else { } else {
in = in =
new BufferedReader(new InputStreamReader( new BufferedReader(new InputStreamReader(
new FileInputStream(sourceFile),
encoding));
new FileInputStream(sourceFile),
encoding));
out = out =
new BufferedWriter(new OutputStreamWriter( new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(destFile),
encoding));
new FileOutputStream(destFile),
encoding));
} }


if (filterChainsAvailable) { if (filterChainsAvailable) {
@@ -555,8 +582,8 @@ public class FileUtils {
if (!onNetWare) { if (!onNetWare) {
if (!path.startsWith(File.separator) && if (!path.startsWith(File.separator) &&
!(path.length() >= 2 && !(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"; String msg = path + " is not an absolute path";
throw new BuildException(msg); throw new BuildException(msg);
} }
@@ -780,7 +807,7 @@ public class FileUtils {
public static final String readFully(Reader rdr, int bufferSize) throws IOException { public static final String readFully(Reader rdr, int bufferSize) throws IOException {
if (bufferSize <= 0) { if (bufferSize <= 0) {
throw new IllegalArgumentException("Buffer size must be greater " throw new IllegalArgumentException("Buffer size must be greater "
+ "than 0");
+ "than 0");
} }
final char[] buffer = new char[bufferSize]; final char[] buffer = new char[bufferSize];
int bufferLength = 0; int bufferLength = 0;
@@ -791,7 +818,7 @@ public class FileUtils {
if (bufferLength != -1) { if (bufferLength != -1) {
if (textBuffer == null) { if (textBuffer == null) {
textBuffer = new StringBuffer( textBuffer = new StringBuffer(
new String(buffer, 0, bufferLength));
new String(buffer, 0, bufferLength));
} else { } else {
textBuffer.append(new String(buffer, 0, bufferLength)); textBuffer.append(new String(buffer, 0, bufferLength));
} }
@@ -875,5 +902,92 @@ public class FileUtils {
return p; 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;
}

} }



+ 15
- 0
src/testcases/org/apache/tools/ant/IncludeTest.java View File

@@ -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'");
}

} }

+ 31
- 0
src/testcases/org/apache/tools/ant/util/FileUtilsTest.java View File

@@ -408,6 +408,37 @@ public class FileUtilsTest extends TestCase {
fu.removeLeadingPath(new File("/foo"), new File("/foobar"))); 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 * adapt file separators to local conventions
*/ */


Loading…
Cancel
Save