Author: bayard Date: Sat Oct 26 02:45:39 2013 New Revision: 1535914 URL: http://svn.apache.org/r1535914 Log: Rewriting OctalUnescaper as a hand rolled parser (all of 4 characters), instead of trying to handle the conversion via repeated attempts to convert the numbers. This fixes bugs, see LANG-929, and also changes the behaviour for 'illegal' octals such as \999. Instead of throwing NumberFormatException, it will now ignore them. This seems the better behaviour.
Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/text/translate/OctalUnescaper.java commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/text/translate/OctalUnescaperTest.java Modified: commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/text/translate/OctalUnescaper.java URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/text/translate/OctalUnescaper.java?rev=1535914&r1=1535913&r2=1535914&view=diff ============================================================================== --- commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/text/translate/OctalUnescaper.java (original) +++ commons/proper/lang/trunk/src/main/java/org/apache/commons/lang3/text/translate/OctalUnescaper.java Sat Oct 26 02:45:39 2013 @@ -40,25 +40,34 @@ public class OctalUnescaper extends Char */ @Override public int translate(final CharSequence input, final int index, final Writer out) throws IOException { - if(input.charAt(index) == '\\' && index < (input.length() - 1) && Character.isDigit(input.charAt(index + 1)) ) { - final int start = index + 1; + int remaining = input.length() - index - 1; // how many characters left, ignoring the first \ + StringBuilder builder = new StringBuilder(); + if(input.charAt(index) == '\\' && remaining > 0 && isOctalDigit(input.charAt(index + 1)) ) { + int next = index + 1; + int next2 = index + 2; + int next3 = index + 3; - int end = index + 2; - while ( end < input.length() && Character.isDigit(input.charAt(end)) ) { - end++; - if ( Integer.parseInt(input.subSequence(start, end).toString(), 10) > OCTAL_MAX) { - end--; // rollback - break; - } - // only 3 characters applicable for Octal - if (end - start >= 3) { - break; + // we know this is good as we checked it in the if block above + builder.append(input.charAt(next)); + + if(remaining > 1 && isOctalDigit(input.charAt(next2))) { + builder.append(input.charAt(next2)); + if(remaining > 2 && isZeroToThree(input.charAt(next)) && isOctalDigit(input.charAt(next3))) { + builder.append(input.charAt(next3)); } } - out.write( Integer.parseInt(input.subSequence(start, end).toString(), 8) ); - return 1 + end - start; + out.write( Integer.parseInt(builder.toString(), 8) ); + return 1 + builder.length(); } return 0; } + + private boolean isOctalDigit(char ch) { + return ch >= '0' && ch <= '7'; + } + + private boolean isZeroToThree(char ch) { + return ch >= '0' && ch <= '3'; + } } Modified: commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/text/translate/OctalUnescaperTest.java URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/text/translate/OctalUnescaperTest.java?rev=1535914&r1=1535913&r2=1535914&view=diff ============================================================================== --- commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/text/translate/OctalUnescaperTest.java (original) +++ commons/proper/lang/trunk/src/test/java/org/apache/commons/lang3/text/translate/OctalUnescaperTest.java Sat Oct 26 02:45:39 2013 @@ -69,19 +69,14 @@ public class OctalUnescaperTest { input = "\\0003"; result = oue.translate(input); assertEquals("Failed to unescape octal characters via the between method", "\000" + "3", result); - } - @Test - public void testOutOfRange() { - final OctalUnescaper oue = new OctalUnescaper(); + input = "\\279"; + result = oue.translate(input); + assertEquals("Failed to unescape octal characters via the between method", "\279", result); - String input = "\\999"; - try { - String result = oue.translate(input); - fail("NumberFormatException was expected for input: " + input); - } catch(NumberFormatException nfe) { - // expected - } + input = "\\999"; + result = oue.translate(input); + assertEquals("Failed to ignore an out of range octal character via the between method", "\\999", result); } }