diff --git a/manual/Tasks/native2ascii.html b/manual/Tasks/native2ascii.html index acbd46085..ecc065a3d 100644 --- a/manual/Tasks/native2ascii.html +++ b/manual/Tasks/native2ascii.html @@ -81,7 +81,7 @@ reverse Reverse the sense of the conversion, i.e. convert from ASCII to native only supported by the - sun converter + sun and builtin converters No diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/BuiltinNative2Ascii.java b/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/BuiltinNative2Ascii.java index b9e600ced..db91a2638 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/BuiltinNative2Ascii.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/native2ascii/BuiltinNative2Ascii.java @@ -23,6 +23,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; +import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; @@ -45,20 +46,15 @@ public class BuiltinNative2Ascii implements Native2AsciiAdapter { public final boolean convert(Native2Ascii args, File srcFile, File destFile) throws BuildException { + boolean reverse = args.getReverse(); + String encoding = args.getEncoding(); BufferedReader input = null; try { - if (args.getEncoding() != null) { - input = new BufferedReader(new InputStreamReader( - new FileInputStream(srcFile), args.getEncoding())); - } else { - input = new BufferedReader(new FileReader(srcFile)); - } + input = getReader(srcFile, encoding, reverse); try { - BufferedWriter output = new BufferedWriter( - new OutputStreamWriter(new FileOutputStream(destFile), - "ASCII")); + Writer output = getWriter(destFile, encoding, reverse); try { - translate(input, output, args.getReverse()); + translate(input, output, reverse); } finally { FileUtils.close(output); } @@ -71,11 +67,37 @@ public class BuiltinNative2Ascii implements Native2AsciiAdapter { } } + private BufferedReader getReader(File srcFile, String encoding, + boolean reverse) throws IOException { + if (!reverse && encoding != null) { + return new BufferedReader(new InputStreamReader( + new FileInputStream(srcFile), encoding)); + } + return new BufferedReader(new FileReader(srcFile)); + } + + private Writer getWriter(File destFile, String encoding, + boolean reverse) throws IOException { + if (!reverse) { + encoding = "ASCII"; + } + if (encoding != null) { + return new BufferedWriter( + new OutputStreamWriter(new FileOutputStream(destFile), + encoding)); + } + return new BufferedWriter(new FileWriter(destFile)); + } + private void translate(BufferedReader input, Writer output, boolean reverse) throws IOException { String line = null; while ((line = input.readLine()) != null) { - output.write(Native2AsciiUtils.native2ascii(line)); + if (!reverse) { + output.write(Native2AsciiUtils.native2ascii(line)); + } else { + output.write(Native2AsciiUtils.ascii2native(line)); + } output.write(StringUtils.LINE_SEP); } } diff --git a/src/main/org/apache/tools/ant/util/Native2AsciiUtils.java b/src/main/org/apache/tools/ant/util/Native2AsciiUtils.java index acdfaaa92..a69d0313d 100644 --- a/src/main/org/apache/tools/ant/util/Native2AsciiUtils.java +++ b/src/main/org/apache/tools/ant/util/Native2AsciiUtils.java @@ -48,4 +48,42 @@ public class Native2AsciiUtils { } return sb.toString(); } + + /** + * Replaces Unicode-Escapes. + *

Expects to be called once per line if applied to a file.

+ * @param line the input line + * @return the translated line + */ + public static String ascii2native(String line) { + StringBuilder sb = new StringBuilder(); + int inputLen = line.length(); + for (int i = 0; i < inputLen; i++) { + char c = line.charAt(i); + if (c != '\\' || i >= inputLen - 5) { + sb.append(c); + } else { // backslash with enough remaining characters + char u = line.charAt(++i); + if (u == 'u') { + int unescaped = tryParse(line, i + 1); + if (unescaped >= 0) { + sb.append((char) unescaped); + i += 4; + continue; + } + } + // not a unicode escape + sb.append(c).append(u); + } + } + return sb.toString(); + } + + private static int tryParse(String line, int startIdx) { + try { + return Integer.parseInt(line.substring(startIdx, startIdx + 4), 16); + } catch (NumberFormatException ex) { + return -1; + } + } } diff --git a/src/tests/antunit/taskdefs/optional/native2ascii-test.xml b/src/tests/antunit/taskdefs/optional/native2ascii-test.xml index 59030e947..be521de7f 100644 --- a/src/tests/antunit/taskdefs/optional/native2ascii-test.xml +++ b/src/tests/antunit/taskdefs/optional/native2ascii-test.xml @@ -95,12 +95,6 @@ public class Adapter implements Native2AsciiAdapter { value="\u00e4\u00f6\u00fc=\u00c4\u00d6\u00dc"/> - - - - - @@ -131,4 +125,11 @@ public class Adapter implements Native2AsciiAdapter { expected="${umlauts.expected}"/> + + + + + diff --git a/src/tests/junit/org/apache/tools/ant/util/Native2AsciiUtilsTest.java b/src/tests/junit/org/apache/tools/ant/util/Native2AsciiUtilsTest.java index 75719f2ab..f3b54e619 100644 --- a/src/tests/junit/org/apache/tools/ant/util/Native2AsciiUtilsTest.java +++ b/src/tests/junit/org/apache/tools/ant/util/Native2AsciiUtilsTest.java @@ -43,4 +43,34 @@ public class Native2AsciiUtilsTest { assertEquals("\\u00e4\\u01f6\\u12fc", Native2AsciiUtils.native2ascii("\u00e4\u01f6\u12fc")); } + + @Test + public void doesntTouchNonEscapes() { + StringBuilder sb = new StringBuilder(); + for (char i = 0; i < 128; i++) { + sb.append(i); + } + assertEquals(sb.toString(), Native2AsciiUtils.ascii2native(sb.toString())); + } + + @Test + public void unescapes() { + assertEquals("\u00e4\u00f6\u00fc", + Native2AsciiUtils.ascii2native("\\u00e4\\u00f6\\u00fc")); + } + + @Test + public void leavesNonUnicodeBackslashesAlone() { + assertEquals("\\abcdef", Native2AsciiUtils.ascii2native("\\abcdef")); + assertEquals("\\u012j", Native2AsciiUtils.ascii2native("\\u012j")); + } + + @Test + public void dealsWithUnfinishedEscapes() { + assertEquals("\u00e4", Native2AsciiUtils.ascii2native("\\u00e4")); + assertEquals("\\u00e", Native2AsciiUtils.ascii2native("\\u00e")); + assertEquals("\\u00", Native2AsciiUtils.ascii2native("\\u00")); + assertEquals("\\u0", Native2AsciiUtils.ascii2native("\\u0")); + } + }