You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2011/01/24 01:46:10 UTC
svn commit: r1062592 - in /commons/proper/codec/trunk/src:
java/org/apache/commons/codec/binary/ test/org/apache/commons/codec/binary/
Author: ggregory
Date: Mon Jan 24 00:46:09 2011
New Revision: 1062592
URL: http://svn.apache.org/viewvc?rev=1062592&view=rev
Log:
[CODEC-105] ArrayIndexOutOfBoundsException when doing multiple reads() on encoding b64InputStream. https://issues.apache.org/jira/browse/CODEC-105
Added:
commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Codec105ErrorInputStream.java
Modified:
commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base64.java
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
Modified: commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base64.java
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base64.java?rev=1062592&r1=1062591&r2=1062592&view=diff
==============================================================================
--- commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base64.java (original)
+++ commons/proper/codec/trunk/src/java/org/apache/commons/codec/binary/Base64.java Mon Jan 24 00:46:09 2011
@@ -406,15 +406,9 @@ public class Base64 implements BinaryEnc
int readResults(byte[] b, int bPos, int bAvail) {
if (buffer != null) {
int len = Math.min(avail(), bAvail);
- if (buffer != b) {
- System.arraycopy(buffer, readPos, b, bPos, len);
- readPos += len;
- if (readPos >= pos) {
- buffer = null;
- }
- } else {
- // Re-using the original consumer's output array is only
- // allowed for one round.
+ System.arraycopy(buffer, readPos, b, bPos, len);
+ readPos += len;
+ if (readPos >= pos) {
buffer = null;
}
return len;
@@ -423,27 +417,6 @@ public class Base64 implements BinaryEnc
}
/**
- * Sets the streaming buffer. This is a small optimization where we try to buffer directly to the consumer's output
- * array for one round (if the consumer calls this method first) instead of starting our own buffer.
- *
- * @param out
- * byte[] array to buffer directly to.
- * @param outPos
- * Position to start buffering into.
- * @param outAvail
- * Amount of bytes available for direct buffering.
- */
- void setInitialBuffer(byte[] out, int outPos, int outAvail) {
- // We can re-use consumer's original output array under
- // special circumstances, saving on some System.arraycopy().
- if (out != null && out.length == outAvail) {
- buffer = out;
- pos = outPos;
- readPos = outPos;
- }
- }
-
- /**
* <p>
* Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least twice: once with
* the data to encode, and once with inAvail set to "-1" to alert encoder that EOF has been reached, so flush last
@@ -493,7 +466,10 @@ public class Base64 implements BinaryEnc
}
break;
}
- if (lineLength > 0 && pos > 0) {
+ // Don't want to append the CRLF two times in a row, so make sure previous
+ // character is not from CRLF!
+ byte b = lineSeparator[lineSeparator.length - 1];
+ if (lineLength > 0 && pos > 0 && buffer[pos-1] != b) {
System.arraycopy(lineSeparator, 0, buffer, pos, lineSeparator.length);
pos += lineSeparator.length;
}
@@ -751,18 +727,8 @@ public class Base64 implements BinaryEnc
if (pArray == null || pArray.length == 0) {
return pArray;
}
- long len = (pArray.length * 3) / 4;
- byte[] buf = new byte[(int) len];
- setInitialBuffer(buf, 0, buf.length);
decode(pArray, 0, pArray.length);
decode(pArray, 0, -1); // Notify decoder of EOF.
-
- // Would be nice to just return buf (like we sometimes do in the encode
- // logic), but we have no idea what the line-length was (could even be
- // variable). So we cannot determine ahead of time exactly how big an
- // array is necessary. Hence the need to construct a 2nd byte array to
- // hold the final result:
-
byte[] result = new byte[pos];
readResults(result, 0, result.length);
return result;
@@ -946,23 +912,11 @@ public class Base64 implements BinaryEnc
if (pArray == null || pArray.length == 0) {
return pArray;
}
- long len = getEncodeLength(pArray, lineLength, lineSeparator);
- byte[] buf = new byte[(int) len];
- setInitialBuffer(buf, 0, buf.length);
encode(pArray, 0, pArray.length);
encode(pArray, 0, -1); // Notify encoder of EOF.
- // Encoder might have resized, even though it was unnecessary.
- if (buffer != buf) {
- readResults(buf, 0, buf.length);
- }
- // In URL-SAFE mode we skip the padding characters, so sometimes our
- // final length is a bit smaller.
- if (isUrlSafe() && pos < buf.length) {
- byte[] smallerBuf = new byte[pos];
- System.arraycopy(buf, 0, smallerBuf, 0, pos);
- buf = smallerBuf;
- }
- return buf;
+ byte[] buf = new byte[pos - readPos];
+ readResults(buf, 0, buf.length);
+ return buf;
}
/**
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=1062592&r1=1062591&r2=1062592&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 Mon Jan 24 00:46:09 2011
@@ -166,11 +166,6 @@ public class Base64InputStream extends F
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 {
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=1062592&r1=1062591&r2=1062592&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 Mon Jan 24 00:46:09 2011
@@ -19,6 +19,7 @@ package org.apache.commons.codec.binary;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
@@ -49,6 +50,16 @@ public class Base64InputStreamTest exten
}
/**
+ * Tests the bug reported in CODEC-105. Bad interactions with InputStream when reading one byte at a time.
+ */
+ public void testCodec105() throws IOException {
+ Base64InputStream in = new Base64InputStream(new Codec105ErrorInputStream(), true, 0, null);
+ for (int i = 0; i < 5; i++) {
+ in.read();
+ }
+ }
+
+ /**
* Test for the CODEC-101 bug: InputStream.read(byte[]) should never return 0
* because Java's builtin InputStreamReader hates that.
*
Added: commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Codec105ErrorInputStream.java
URL: http://svn.apache.org/viewvc/commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Codec105ErrorInputStream.java?rev=1062592&view=auto
==============================================================================
--- commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Codec105ErrorInputStream.java (added)
+++ commons/proper/codec/trunk/src/test/org/apache/commons/codec/binary/Codec105ErrorInputStream.java Mon Jan 24 00:46:09 2011
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.codec.binary;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Emits three line-feeds '\n' in a row, one at a time, and then EOF.
+ *
+ * Recreates the bug described in CODEC-105.
+ *
+ * @author Apache Software Foundation
+ * @version $Id $
+ * @since 1.5
+ */
+public class Codec105ErrorInputStream extends InputStream {
+ private static final int EOF = -1;
+
+ int countdown = 3;
+
+ public int read() throws IOException {
+ if (this.countdown-- > 0) {
+ return '\n';
+ } else {
+ return EOF;
+ }
+ }
+
+ public int read(byte b[], int pos, int len) throws IOException {
+ if (this.countdown-- > 0) {
+ b[pos] = '\n';
+ return 1;
+ } else {
+ return EOF;
+ }
+ }
+}