Author: julius Date: Fri Jan 21 19:19:51 2011 New Revision: 1061974 URL: http://svn.apache.org/viewvc?rev=1061974&view=rev Log: Fix for CODEC-101: java.io.InputStreamReader hates it when InputStream.read(byte[]) returns a zero.
Modified: commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base64InputStream.java commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Base64InputStreamTest.java commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Base64TestData.java Modified: commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base64InputStream.java URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base64InputStream.java?rev=1061974&r1=1061973&r2=1061974&view=diff ============================================================================== --- commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base64InputStream.java (original) +++ commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base64InputStream.java Fri Jan 21 19:19:51 2011 @@ -145,21 +145,41 @@ public class Base64InputStream extends F } else if (len == 0) { return 0; } else { - if (!base64.hasData()) { - byte[] buf = new byte[doEncode ? 4096 : 8192]; - int c = in.read(buf); - // A little optimization to avoid System.arraycopy() - // when possible. - if (c > 0 && b.length == len) { - base64.setInitialBuffer(b, offset, len); - } - if (doEncode) { - base64.encode(buf, 0, c); - } else { - base64.decode(buf, 0, c); + int readLen = 0; + /* + Rationale for while-loop on (readLen == 0): + ----- + Base64.readResults() usually returns > 0 or EOF (-1). In the + rare case where it returns 0, we just keep trying. + + This is essentially an undocumented contract for InputStream + implementors that want their code to work properly with + java.io.InputStreamReader, since the latter hates it when + InputStream.read(byte[]) returns a zero. Unfortunately our + readResults() call must return 0 if a large amount of the data + being decoded was non-base64, so this while-loop enables proper + interop with InputStreamReader for that scenario. + ----- + This is a fix for CODEC-101 + */ + while (readLen == 0) { + if (!base64.hasData()) { + byte[] buf = new byte[doEncode ? 4096 : 8192]; + int c = in.read(buf); + // A little optimization to avoid System.arraycopy() + // when possible. + if (c > 0 && b.length == len) { + base64.setInitialBuffer(b, offset, len); + } + if (doEncode) { + base64.encode(buf, 0, c); + } else { + base64.decode(buf, 0, c); + } } + readLen = base64.readResults(b, offset, len); } - return base64.readResults(b, offset, len); + return readLen; } } Modified: commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Base64InputStreamTest.java URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Base64InputStreamTest.java?rev=1061974&r1=1061973&r2=1061974&view=diff ============================================================================== --- commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Base64InputStreamTest.java (original) +++ commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Base64InputStreamTest.java Fri Jan 21 19:19:51 2011 @@ -47,6 +47,24 @@ public class Base64InputStreamTest exten } /** + * Test for the CODEC-101 bug: InputStream.read(byte[]) should never return 0 + * because Java's builtin InputStreamReader hates that. + * + * @throws Exception for some failure scenarios. + */ + public void testCodec101() throws Exception { + byte[] codec101 = StringUtils.getBytesUtf8(Base64TestData.CODEC_101_MULTIPLE_OF_3); + ByteArrayInputStream bais = new ByteArrayInputStream(codec101); + Base64InputStream in = new Base64InputStream(bais); + byte[] result = new byte[8192]; + int c = in.read(result); + assertTrue("Codec101: First read successful [c=" + c + "]", c > 0); + + c = in.read(result); + assertTrue("Codec101: Second read should report end-of-stream [c=" + c + "]", c < 0); + } + + /** * Test the Base64InputStream implementation against the special NPE inducing input * identified in the CODEC-98 bug. * Modified: commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Base64TestData.java URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Base64TestData.java?rev=1061974&r1=1061973&r2=1061974&view=diff ============================================================================== --- commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Base64TestData.java (original) +++ commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Base64TestData.java Fri Jan 21 19:19:51 2011 @@ -32,6 +32,8 @@ import java.util.Random; */ public class Base64TestData { + public static final String CODEC_101_MULTIPLE_OF_3 = "123"; + public static final String CODEC_98_NPE = "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWjAxMjM";