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.
git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@1535914 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
6ea7f2f7af
commit
2550d4cfa2
|
@ -40,25 +40,34 @@ public class OctalUnescaper extends CharSequenceTranslator {
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public int translate(final CharSequence input, final int index, final Writer out) throws IOException {
|
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)) ) {
|
int remaining = input.length() - index - 1; // how many characters left, ignoring the first \
|
||||||
final int start = index + 1;
|
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;
|
// we know this is good as we checked it in the if block above
|
||||||
while ( end < input.length() && Character.isDigit(input.charAt(end)) ) {
|
builder.append(input.charAt(next));
|
||||||
end++;
|
|
||||||
if ( Integer.parseInt(input.subSequence(start, end).toString(), 10) > OCTAL_MAX) {
|
if(remaining > 1 && isOctalDigit(input.charAt(next2))) {
|
||||||
end--; // rollback
|
builder.append(input.charAt(next2));
|
||||||
break;
|
if(remaining > 2 && isZeroToThree(input.charAt(next)) && isOctalDigit(input.charAt(next3))) {
|
||||||
}
|
builder.append(input.charAt(next3));
|
||||||
// only 3 characters applicable for Octal
|
|
||||||
if (end - start >= 3) {
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
out.write( Integer.parseInt(input.subSequence(start, end).toString(), 8) );
|
out.write( Integer.parseInt(builder.toString(), 8) );
|
||||||
return 1 + end - start;
|
return 1 + builder.length();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isOctalDigit(char ch) {
|
||||||
|
return ch >= '0' && ch <= '7';
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isZeroToThree(char ch) {
|
||||||
|
return ch >= '0' && ch <= '3';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,19 +69,14 @@ public void testBetween() {
|
||||||
input = "\\0003";
|
input = "\\0003";
|
||||||
result = oue.translate(input);
|
result = oue.translate(input);
|
||||||
assertEquals("Failed to unescape octal characters via the between method", "\000" + "3", result);
|
assertEquals("Failed to unescape octal characters via the between method", "\000" + "3", result);
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
input = "\\279";
|
||||||
public void testOutOfRange() {
|
result = oue.translate(input);
|
||||||
final OctalUnescaper oue = new OctalUnescaper();
|
assertEquals("Failed to unescape octal characters via the between method", "\279", result);
|
||||||
|
|
||||||
String input = "\\999";
|
input = "\\999";
|
||||||
try {
|
result = oue.translate(input);
|
||||||
String result = oue.translate(input);
|
assertEquals("Failed to ignore an out of range octal character via the between method", "\\999", result);
|
||||||
fail("NumberFormatException was expected for input: " + input);
|
|
||||||
} catch(NumberFormatException nfe) {
|
|
||||||
// expected
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue