This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-codec.git
The following commit(s) were added to refs/heads/master by this push: new 9f1b740 Reimplement the new-in-1.15 BaseNCodec's and friends' strict vs. lenient decoding as final instance variables and with an enum instead of a boolean. Introduce the last amount of new constructors. 9f1b740 is described below commit 9f1b740a17f0d54366edfb45df0636b8e302666a Author: Gary Gregory <garydgreg...@gmail.com> AuthorDate: Sun May 17 11:51:25 2020 -0400 Reimplement the new-in-1.15 BaseNCodec's and friends' strict vs. lenient decoding as final instance variables and with an enum instead of a boolean. Introduce the last amount of new constructors. --- .../java/org/apache/commons/codec/CodecPolicy.java | 36 +++++++ .../org/apache/commons/codec/binary/Base32.java | 60 +++++++---- .../commons/codec/binary/Base32InputStream.java | 43 +++++++- .../commons/codec/binary/Base32OutputStream.java | 42 +++++++- .../org/apache/commons/codec/binary/Base64.java | 56 +++++++--- .../commons/codec/binary/Base64InputStream.java | 42 +++++++- .../commons/codec/binary/Base64OutputStream.java | 42 +++++++- .../apache/commons/codec/binary/BaseNCodec.java | 119 +++++++++++++++------ .../codec/binary/BaseNCodecInputStream.java | 20 ---- .../codec/binary/BaseNCodecOutputStream.java | 20 ---- .../java/org/apache/commons/codec/net/BCodec.java | 52 ++++----- .../codec/binary/Base32InputStreamTest.java | 4 +- .../codec/binary/Base32OutputStreamTest.java | 14 +-- .../apache/commons/codec/binary/Base32Test.java | 17 +-- .../codec/binary/Base64InputStreamTest.java | 4 +- .../codec/binary/Base64OutputStreamTest.java | 18 ++-- .../apache/commons/codec/binary/Base64Test.java | 7 +- .../org/apache/commons/codec/net/BCodecTest.java | 22 +++- 18 files changed, 451 insertions(+), 167 deletions(-) diff --git a/src/main/java/org/apache/commons/codec/CodecPolicy.java b/src/main/java/org/apache/commons/codec/CodecPolicy.java new file mode 100644 index 0000000..9cf5e12 --- /dev/null +++ b/src/main/java/org/apache/commons/codec/CodecPolicy.java @@ -0,0 +1,36 @@ +/* + * 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; + +/** + * Defines encoding and decoding policies. + * + * @since 1.15 + */ +public enum CodecPolicy { + + /** + * The strict policy. Data that causes a codec to fail should throw an exception. + */ + STRICT, + + /** + * The strict policy. Data that causes a codec to fail should not throw an exception. + */ + LENIENT +} diff --git a/src/main/java/org/apache/commons/codec/binary/Base32.java b/src/main/java/org/apache/commons/codec/binary/Base32.java index aa5d3e4..8d57861 100644 --- a/src/main/java/org/apache/commons/codec/binary/Base32.java +++ b/src/main/java/org/apache/commons/codec/binary/Base32.java @@ -17,6 +17,8 @@ package org.apache.commons.codec.binary; +import org.apache.commons.codec.CodecPolicy; + /** * Provides Base32 encoding and decoding as defined by <a href="http://www.ietf.org/rfc/rfc4648.txt">RFC 4648</a>. * @@ -52,13 +54,6 @@ public class Base32 extends BaseNCodec { private static final int BYTES_PER_UNENCODED_BLOCK = 5; /** - * Chunk separator per RFC 2045 section 2.1. - * - * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a> - */ - private static final byte[] CHUNK_SEPARATOR = {'\r', '\n'}; - - /** * This array is a lookup table that translates Unicode characters drawn from the "Base32 Alphabet" (as specified * in Table 3 of RFC 4648) into their 5-bit positive integer equivalents. Characters that are not in the Base32 * alphabet but fall within the bounds of the array are translated to -1. @@ -200,10 +195,10 @@ public class Base32 extends BaseNCodec { * When encoding the line length is 0 (no chunking). * </p> * @param useHex if {@code true} then use Base32 Hex alphabet - * @param pad byte used as padding byte. + * @param padding byte used as padding byte. */ - public Base32(final boolean useHex, final byte pad) { - this(0, null, useHex, pad); + public Base32(final boolean useHex, final byte padding) { + this(0, null, useHex, padding); } /** @@ -237,7 +232,7 @@ public class Base32 extends BaseNCodec { * @param lineSeparator * Each line of encoded data will end with this sequence of bytes. * @throws IllegalArgumentException - * The provided lineSeparator included some Base32 characters. That's not going to work! + * Thrown when the {@code lineSeparator} contains Base32 characters. */ public Base32(final int lineLength, final byte[] lineSeparator) { this(lineLength, lineSeparator, false, PAD_DEFAULT); @@ -261,7 +256,7 @@ public class Base32 extends BaseNCodec { * @param useHex * if {@code true}, then use Base32 Hex alphabet, otherwise use Base32 alphabet * @throws IllegalArgumentException - * The provided lineSeparator included some Base32 characters. That's not going to work! Or the + * Thrown when the {@code lineSeparator} contains Base32 characters. Or the * lineLength > 0 and lineSeparator is null. */ public Base32(final int lineLength, final byte[] lineSeparator, final boolean useHex) { @@ -285,14 +280,41 @@ public class Base32 extends BaseNCodec { * Each line of encoded data will end with this sequence of bytes. * @param useHex * if {@code true}, then use Base32 Hex alphabet, otherwise use Base32 alphabet - * @param pad byte used as padding byte. + * @param padding byte used as padding byte. + * @throws IllegalArgumentException + * Thrown when the {@code lineSeparator} contains Base32 characters. Or the + * lineLength > 0 and lineSeparator is null. + */ + public Base32(final int lineLength, final byte[] lineSeparator, final boolean useHex, final byte padding) { + this(lineLength, lineSeparator, useHex, padding, DECODING_POLICY_DEFAULT); + } + + /** + * Creates a Base32 / Base32 Hex codec used for decoding and encoding. + * <p> + * When encoding the line length and line separator are given in the constructor. + * </p> + * <p> + * Line lengths that aren't multiples of 8 will still essentially end up being multiples of 8 in the encoded data. + * </p> + * + * @param lineLength + * Each line of encoded data will be at most of the given length (rounded down to nearest multiple of + * 8). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when + * decoding. + * @param lineSeparator + * Each line of encoded data will end with this sequence of bytes. + * @param useHex + * if {@code true}, then use Base32 Hex alphabet, otherwise use Base32 alphabet + * @param padding byte used as padding byte. + * @param decodingPolicy The decoding policy. * @throws IllegalArgumentException - * The provided lineSeparator included some Base32 characters. That's not going to work! Or the + * Thrown when the {@code lineSeparator} contains Base32 characters. Or the * lineLength > 0 and lineSeparator is null. */ - public Base32(final int lineLength, final byte[] lineSeparator, final boolean useHex, final byte pad) { + public Base32(final int lineLength, final byte[] lineSeparator, final boolean useHex, final byte padding, CodecPolicy decodingPolicy) { super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, lineLength, - lineSeparator == null ? 0 : lineSeparator.length, pad); + lineSeparator == null ? 0 : lineSeparator.length, padding, decodingPolicy); if (useHex) { this.encodeTable = HEX_ENCODE_TABLE; this.decodeTable = HEX_DECODE_TABLE; @@ -318,7 +340,7 @@ public class Base32 extends BaseNCodec { } this.decodeSize = this.encodeSize - 1; - if (isInAlphabet(pad) || isWhiteSpace(pad)) { + if (isInAlphabet(padding) || isWhiteSpace(padding)) { throw new IllegalArgumentException("pad must not be in alphabet or whitespace"); } } @@ -436,7 +458,7 @@ public class Base32 extends BaseNCodec { break; default: // modulus can be 0-7, and we excluded 0,1 already - throw new IllegalStateException("Impossible modulus "+context.modulus); + throw new IllegalStateException("Impossible modulus " + context.modulus); } } } @@ -516,7 +538,7 @@ public class Base32 extends BaseNCodec { buffer[context.pos++] = pad; break; default: - throw new IllegalStateException("Impossible modulus "+context.modulus); + throw new IllegalStateException("Impossible modulus " + context.modulus); } context.currentLinePos += context.pos - savedPos; // keep track of current line position // if currentPos == 0 we are at the start of a line, so don't add CRLF diff --git a/src/main/java/org/apache/commons/codec/binary/Base32InputStream.java b/src/main/java/org/apache/commons/codec/binary/Base32InputStream.java index 0be8860..92a6a74 100644 --- a/src/main/java/org/apache/commons/codec/binary/Base32InputStream.java +++ b/src/main/java/org/apache/commons/codec/binary/Base32InputStream.java @@ -19,6 +19,8 @@ package org.apache.commons.codec.binary; import java.io.InputStream; +import org.apache.commons.codec.CodecPolicy; + /** * Provides Base32 encoding and decoding in a streaming fashion (unlimited size). When encoding the default lineLength * is 76 characters and the default lineEnding is CRLF, but these can be overridden by using the appropriate @@ -31,7 +33,22 @@ import java.io.InputStream; * Since this class operates directly on byte streams, and not character streams, it is hard-coded to only encode/decode * character encodings which are compatible with the lower 127 ASCII chart (ISO-8859-1, Windows-1252, UTF-8, etc). * </p> - * + * <p> + * You can set the decoding behavior when the input bytes contain leftover trailing bits that cannot be created by a valid + * encoding. These can be bits that are unused from the final character or entire characters. The default mode is + * lenient decoding. + * </p> + * <ul> + * <li>Lenient: Any trailing bits are composed into 8-bit bytes where possible. The remainder are discarded. + * <li>Strict: The decoding will raise an {@link IllegalArgumentException} if trailing bits are not part of a valid + * encoding. Any unused bits from the final character must be zero. Impossible counts of entire final characters are not + * allowed. + * </ul> + * <p> + * When strict decoding is enabled it is expected that the decoded bytes will be re-encoded to a byte array that matches + * the original, i.e. no changes occur on the final character. This requires that the input bytes use the same padding + * and alphabet as the encoder. + * </p> * @see <a href="http://www.ietf.org/rfc/rfc4648.txt">RFC 4648</a> * @since 1.5 */ @@ -81,4 +98,28 @@ public class Base32InputStream extends BaseNCodecInputStream { super(input, new Base32(lineLength, lineSeparator), doEncode); } + /** + * Creates a Base32InputStream such that all data read is either Base32-encoded or Base32-decoded from the original + * provided InputStream. + * + * @param input + * InputStream to wrap. + * @param doEncode + * true if we should encode all data read from us, false if we should decode. + * @param lineLength + * If doEncode is true, each line of encoded data will contain lineLength characters (rounded down to + * nearest multiple of 4). If lineLength <= 0, the encoded data is not divided into lines. If doEncode + * is false, lineLength is ignored. + * @param lineSeparator + * If doEncode is true, each line of encoded data will be terminated with this byte sequence (e.g. \r\n). + * If lineLength <= 0, the lineSeparator is not used. If doEncode is false lineSeparator is ignored. + * @param decodingPolicy + * The decoding policy. + * @since 1.15 + */ + public Base32InputStream(final InputStream input, final boolean doEncode, + final int lineLength, final byte[] lineSeparator, final CodecPolicy decodingPolicy) { + super(input, new Base32(lineLength, lineSeparator, false, BaseNCodec.PAD_DEFAULT, decodingPolicy), doEncode); + } + } diff --git a/src/main/java/org/apache/commons/codec/binary/Base32OutputStream.java b/src/main/java/org/apache/commons/codec/binary/Base32OutputStream.java index be0a7a4..a553a7d 100644 --- a/src/main/java/org/apache/commons/codec/binary/Base32OutputStream.java +++ b/src/main/java/org/apache/commons/codec/binary/Base32OutputStream.java @@ -19,6 +19,8 @@ package org.apache.commons.codec.binary; import java.io.OutputStream; +import org.apache.commons.codec.CodecPolicy; + /** * Provides Base32 encoding and decoding in a streaming fashion (unlimited size). When encoding the default lineLength * is 76 characters and the default lineEnding is CRLF, but these can be overridden by using the appropriate @@ -35,7 +37,22 @@ import java.io.OutputStream; * <b>Note:</b> It is mandatory to close the stream after the last byte has been written to it, otherwise the * final padding will be omitted and the resulting data will be incomplete/inconsistent. * </p> - * + * <p> + * You can set the decoding behavior when the input bytes contain leftover trailing bits that cannot be created by a valid + * encoding. These can be bits that are unused from the final character or entire characters. The default mode is + * lenient decoding. + * </p> + * <ul> + * <li>Lenient: Any trailing bits are composed into 8-bit bytes where possible. The remainder are discarded. + * <li>Strict: The decoding will raise an {@link IllegalArgumentException} if trailing bits are not part of a valid + * encoding. Any unused bits from the final character must be zero. Impossible counts of entire final characters are not + * allowed. + * </ul> + * <p> + * When strict decoding is enabled it is expected that the decoded bytes will be re-encoded to a byte array that matches + * the original, i.e. no changes occur on the final character. This requires that the input bytes use the same padding + * and alphabet as the encoder. + * </p> * @see <a href="http://www.ietf.org/rfc/rfc4648.txt">RFC 4648</a> * @since 1.5 */ @@ -85,4 +102,27 @@ public class Base32OutputStream extends BaseNCodecOutputStream { super(ouput, new Base32(lineLength, lineSeparator), doEncode); } + /** + * Creates a Base32OutputStream such that all data written is either Base32-encoded or Base32-decoded to the + * original provided OutputStream. + * + * @param ouput + * OutputStream to wrap. + * @param doEncode + * true if we should encode all data written to us, false if we should decode. + * @param lineLength + * If doEncode is true, each line of encoded data will contain lineLength characters (rounded down to + * nearest multiple of 4). If lineLength <= 0, the encoded data is not divided into lines. If doEncode + * is false, lineLength is ignored. + * @param lineSeparator + * If doEncode is true, each line of encoded data will be terminated with this byte sequence (e.g. \r\n). + * If lineLength <= 0, the lineSeparator is not used. If doEncode is false lineSeparator is ignored. + * @param decodingPolicy The decoding policy. + * @since 1.15 + */ + public Base32OutputStream(final OutputStream ouput, final boolean doEncode, + final int lineLength, final byte[] lineSeparator, final CodecPolicy decodingPolicy) { + super(ouput, new Base32(lineLength, lineSeparator, false, BaseNCodec.PAD_DEFAULT, decodingPolicy), doEncode); + } + } diff --git a/src/main/java/org/apache/commons/codec/binary/Base64.java b/src/main/java/org/apache/commons/codec/binary/Base64.java index 5311207..178633d 100644 --- a/src/main/java/org/apache/commons/codec/binary/Base64.java +++ b/src/main/java/org/apache/commons/codec/binary/Base64.java @@ -20,6 +20,8 @@ package org.apache.commons.codec.binary; import java.math.BigInteger; import java.util.Objects; +import org.apache.commons.codec.CodecPolicy; + /** * Provides Base64 encoding and decoding as defined by <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>. * @@ -63,17 +65,6 @@ public class Base64 extends BaseNCodec { private static final int BYTES_PER_ENCODED_BLOCK = 4; /** - * Chunk separator per RFC 2045 section 2.1. - * - * <p> - * N.B. The next major release may break compatibility and make this field private. - * </p> - * - * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a> - */ - static final byte[] CHUNK_SEPARATOR = {'\r', '\n'}; - - /** * This array is a lookup table that translates 6-bit positive integer index values into their "Base64 Alphabet" * equivalents as specified in Table 1 of RFC 2045. * @@ -272,13 +263,47 @@ public class Base64 extends BaseNCodec { * operations. Decoding seamlessly handles both modes. * <b>Note: no padding is added when using the URL-safe alphabet.</b> * @throws IllegalArgumentException - * The provided lineSeparator included some base64 characters. That's not going to work! + * Thrown when the {@code lineSeparator} contains Base64 characters. * @since 1.4 */ public Base64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe) { + this(lineLength, lineSeparator, urlSafe, DECODING_POLICY_DEFAULT); + } + + /** + * Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode. + * <p> + * When encoding the line length and line separator are given in the constructor, and the encoding table is + * STANDARD_ENCODE_TABLE. + * </p> + * <p> + * Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data. + * </p> + * <p> + * When decoding all variants are supported. + * </p> + * + * @param lineLength + * Each line of encoded data will be at most of the given length (rounded down to nearest multiple of + * 4). If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when + * decoding. + * @param lineSeparator + * Each line of encoded data will end with this sequence of bytes. + * @param urlSafe + * Instead of emitting '+' and '/' we emit '-' and '_' respectively. urlSafe is only applied to encode + * operations. Decoding seamlessly handles both modes. + * <b>Note: no padding is added when using the URL-safe alphabet.</b> + * @param decodingPolicy The decoding policy. + * @throws IllegalArgumentException + * Thrown when the {@code lineSeparator} contains Base64 characters. + * @since 1.15 + */ + public Base64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe, final CodecPolicy decodingPolicy) { super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, lineLength, - lineSeparator == null ? 0 : lineSeparator.length); + lineSeparator == null ? 0 : lineSeparator.length, + PAD_DEFAULT, + decodingPolicy); // TODO could be simplified if there is no requirement to reject invalid line sep when length <=0 // @see test case Base64Test.testConstructors() if (lineSeparator != null) { @@ -372,7 +397,7 @@ public class Base64 extends BaseNCodec { } break; default: - throw new IllegalStateException("Impossible modulus "+context.modulus); + throw new IllegalStateException("Impossible modulus " + context.modulus); } context.currentLinePos += context.pos - savedPos; // keep track of current line position // if currentPos == 0 we are at the start of a line, so don't add CRLF @@ -485,7 +510,7 @@ public class Base64 extends BaseNCodec { buffer[context.pos++] = (byte) ((context.ibitWorkArea) & MASK_8BITS); break; default: - throw new IllegalStateException("Impossible modulus "+context.modulus); + throw new IllegalStateException("Impossible modulus " + context.modulus); } } } @@ -819,4 +844,5 @@ public class Base64 extends BaseNCodec { "Expected the discarded bits from the character to be zero."); } } + } diff --git a/src/main/java/org/apache/commons/codec/binary/Base64InputStream.java b/src/main/java/org/apache/commons/codec/binary/Base64InputStream.java index 0a09bd8..7755ce1 100644 --- a/src/main/java/org/apache/commons/codec/binary/Base64InputStream.java +++ b/src/main/java/org/apache/commons/codec/binary/Base64InputStream.java @@ -19,6 +19,8 @@ package org.apache.commons.codec.binary; import java.io.InputStream; +import org.apache.commons.codec.CodecPolicy; + /** * Provides Base64 encoding and decoding in a streaming fashion (unlimited size). When encoding the default lineLength * is 76 characters and the default lineEnding is CRLF, but these can be overridden by using the appropriate @@ -35,7 +37,22 @@ import java.io.InputStream; * Since this class operates directly on byte streams, and not character streams, it is hard-coded to only encode/decode * character encodings which are compatible with the lower 127 ASCII chart (ISO-8859-1, Windows-1252, UTF-8, etc). * </p> - * + * <p> + * You can set the decoding behavior when the input bytes contain leftover trailing bits that cannot be created by a valid + * encoding. These can be bits that are unused from the final character or entire characters. The default mode is + * lenient decoding. + * </p> + * <ul> + * <li>Lenient: Any trailing bits are composed into 8-bit bytes where possible. The remainder are discarded. + * <li>Strict: The decoding will raise an {@link IllegalArgumentException} if trailing bits are not part of a valid + * encoding. Any unused bits from the final character must be zero. Impossible counts of entire final characters are not + * allowed. + * </ul> + * <p> + * When strict decoding is enabled it is expected that the decoded bytes will be re-encoded to a byte array that matches + * the original, i.e. no changes occur on the final character. This requires that the input bytes use the same padding + * and alphabet as the encoder. + * </p> * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a> * @since 1.4 */ @@ -84,4 +101,27 @@ public class Base64InputStream extends BaseNCodecInputStream { final int lineLength, final byte[] lineSeparator) { super(in, new Base64(lineLength, lineSeparator), doEncode); } + + /** + * Creates a Base64InputStream such that all data read is either Base64-encoded or Base64-decoded from the original + * provided InputStream. + * + * @param in + * InputStream to wrap. + * @param doEncode + * true if we should encode all data read from us, false if we should decode. + * @param lineLength + * If doEncode is true, each line of encoded data will contain lineLength characters (rounded down to + * nearest multiple of 4). If lineLength <= 0, the encoded data is not divided into lines. If doEncode + * is false, lineLength is ignored. + * @param lineSeparator + * If doEncode is true, each line of encoded data will be terminated with this byte sequence (e.g. \r\n). + * If lineLength <= 0, the lineSeparator is not used. If doEncode is false lineSeparator is ignored. + * @param decodingPolicy The decoding policy. + * @since 1.15 + */ + public Base64InputStream(final InputStream in, final boolean doEncode, + final int lineLength, final byte[] lineSeparator, final CodecPolicy decodingPolicy) { + super(in, new Base64(lineLength, lineSeparator, false, decodingPolicy), doEncode); + } } diff --git a/src/main/java/org/apache/commons/codec/binary/Base64OutputStream.java b/src/main/java/org/apache/commons/codec/binary/Base64OutputStream.java index 07d6b5c..aa9be55 100644 --- a/src/main/java/org/apache/commons/codec/binary/Base64OutputStream.java +++ b/src/main/java/org/apache/commons/codec/binary/Base64OutputStream.java @@ -19,6 +19,8 @@ package org.apache.commons.codec.binary; import java.io.OutputStream; +import org.apache.commons.codec.CodecPolicy; + /** * Provides Base64 encoding and decoding in a streaming fashion (unlimited size). When encoding the default lineLength * is 76 characters and the default lineEnding is CRLF, but these can be overridden by using the appropriate @@ -39,7 +41,22 @@ import java.io.OutputStream; * <b>Note:</b> It is mandatory to close the stream after the last byte has been written to it, otherwise the * final padding will be omitted and the resulting data will be incomplete/inconsistent. * </p> - * + * <p> + * You can set the decoding behavior when the input bytes contain leftover trailing bits that cannot be created by a valid + * encoding. These can be bits that are unused from the final character or entire characters. The default mode is + * lenient decoding. + * </p> + * <ul> + * <li>Lenient: Any trailing bits are composed into 8-bit bytes where possible. The remainder are discarded. + * <li>Strict: The decoding will raise an {@link IllegalArgumentException} if trailing bits are not part of a valid + * encoding. Any unused bits from the final character must be zero. Impossible counts of entire final characters are not + * allowed. + * </ul> + * <p> + * When strict decoding is enabled it is expected that the decoded bytes will be re-encoded to a byte array that matches + * the original, i.e. no changes occur on the final character. This requires that the input bytes use the same padding + * and alphabet as the encoder. + * </p> * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a> * @since 1.4 */ @@ -88,4 +105,27 @@ public class Base64OutputStream extends BaseNCodecOutputStream { final int lineLength, final byte[] lineSeparator) { super(out, new Base64(lineLength, lineSeparator), doEncode); } + + /** + * Creates a Base64OutputStream such that all data written is either Base64-encoded or Base64-decoded to the + * original provided OutputStream. + * + * @param out + * OutputStream to wrap. + * @param doEncode + * true if we should encode all data written to us, false if we should decode. + * @param lineLength + * If doEncode is true, each line of encoded data will contain lineLength characters (rounded down to + * nearest multiple of 4). If lineLength <= 0, the encoded data is not divided into lines. If doEncode + * is false, lineLength is ignored. + * @param lineSeparator + * If doEncode is true, each line of encoded data will be terminated with this byte sequence (e.g. \r\n). + * If lineLength <= 0, the lineSeparator is not used. If doEncode is false lineSeparator is ignored. + * @param decodingPolicy The decoding policy. + * @since 1.15 + */ + public Base64OutputStream(final OutputStream out, final boolean doEncode, + final int lineLength, final byte[] lineSeparator, final CodecPolicy decodingPolicy) { + super(out, new Base64(lineLength, lineSeparator, false, decodingPolicy), doEncode); + } } diff --git a/src/main/java/org/apache/commons/codec/binary/BaseNCodec.java b/src/main/java/org/apache/commons/codec/binary/BaseNCodec.java index 4c983c6..b45437d 100644 --- a/src/main/java/org/apache/commons/codec/binary/BaseNCodec.java +++ b/src/main/java/org/apache/commons/codec/binary/BaseNCodec.java @@ -18,9 +18,11 @@ package org.apache.commons.codec.binary; import java.util.Arrays; +import java.util.Objects; import org.apache.commons.codec.BinaryDecoder; import org.apache.commons.codec.BinaryEncoder; +import org.apache.commons.codec.CodecPolicy; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.EncoderException; @@ -31,6 +33,20 @@ import org.apache.commons.codec.EncoderException; * This class is thread-safe. * </p> * + * You can set the decoding behavior when the input bytes contain leftover trailing bits that cannot be created by a valid + * encoding. These can be bits that are unused from the final character or entire characters. The default mode is + * lenient decoding. + * <ul> + * <li>Lenient: Any trailing bits are composed into 8-bit bytes where possible. The remainder are discarded. + * <li>Strict: The decoding will raise an {@link IllegalArgumentException} if trailing bits are not part of a valid + * encoding. Any unused bits from the final character must be zero. Impossible counts of entire final characters are not + * allowed. + * </ul> + * <p> + * When strict decoding is enabled it is expected that the decoded bytes will be re-encoded to a byte array that matches + * the original, i.e. no changes occur on the final character. This requires that the input bytes use the same padding + * and alphabet as the encoder. + * </p> */ public abstract class BaseNCodec implements BinaryEncoder, BinaryDecoder { @@ -165,6 +181,18 @@ public abstract class BaseNCodec implements BinaryEncoder, BinaryDecoder { protected static final byte PAD_DEFAULT = '='; // Allow static access to default /** + * The default decoding policy. + */ + protected static final CodecPolicy DECODING_POLICY_DEFAULT = CodecPolicy.LENIENT; + + /** + * Chunk separator per RFC 2045 section 2.1. + * + * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a> + */ + static final byte[] CHUNK_SEPARATOR = {'\r', '\n'}; + + /** * @deprecated Use {@link #pad}. Will be removed in 2.0. */ @Deprecated @@ -191,10 +219,24 @@ public abstract class BaseNCodec implements BinaryEncoder, BinaryDecoder { private final int chunkSeparatorLength; /** - * If true then decoding should throw an exception for impossible combinations of bits at the - * end of the byte input. The default is to decode as much of them as possible. + * Defines the decoding behavior when the input bytes contain leftover trailing bits that + * cannot be created by a valid encoding. These can be bits that are unused from the final + * character or entire characters. The default mode is lenient decoding. Set this to + * {@code true} to enable strict decoding. + * <ul> + * <li>Lenient: Any trailing bits are composed into 8-bit bytes where possible. + * The remainder are discarded. + * <li>Strict: The decoding will raise an {@link IllegalArgumentException} if trailing bits + * are not part of a valid encoding. Any unused bits from the final character must + * be zero. Impossible counts of entire final characters are not allowed. + * </ul> + * + * <p>When strict decoding is enabled it is expected that the decoded bytes will be re-encoded + * to a byte array that matches the original, i.e. no changes occur on the final + * character. This requires that the input bytes use the same padding and alphabet + * as the encoder. */ - private boolean strictDecoding; + private final CodecPolicy decodingPolicy; /** * Note {@code lineLength} is rounded down to the nearest multiple of the encoded block size. @@ -220,54 +262,60 @@ public abstract class BaseNCodec implements BinaryEncoder, BinaryDecoder { */ protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize, final int lineLength, final int chunkSeparatorLength, final byte pad) { + this(unencodedBlockSize, encodedBlockSize, lineLength, chunkSeparatorLength, pad, DECODING_POLICY_DEFAULT); + } + + /** + * Note {@code lineLength} is rounded down to the nearest multiple of the encoded block size. + * If {@code chunkSeparatorLength} is zero, then chunking is disabled. + * @param unencodedBlockSize the size of an unencoded block (e.g. Base64 = 3) + * @param encodedBlockSize the size of an encoded block (e.g. Base64 = 4) + * @param lineLength if > 0, use chunking with a length {@code lineLength} + * @param chunkSeparatorLength the chunk separator length, if relevant + * @param pad byte used as padding byte. + * @param decodingPolicy Decoding policy. + * @since 1.15 + */ + protected BaseNCodec(final int unencodedBlockSize, final int encodedBlockSize, + final int lineLength, final int chunkSeparatorLength, final byte pad, final CodecPolicy decodingPolicy) { this.unencodedBlockSize = unencodedBlockSize; this.encodedBlockSize = encodedBlockSize; final boolean useChunking = lineLength > 0 && chunkSeparatorLength > 0; this.lineLength = useChunking ? (lineLength / encodedBlockSize) * encodedBlockSize : 0; this.chunkSeparatorLength = chunkSeparatorLength; - this.pad = pad; + this.decodingPolicy = Objects.requireNonNull(decodingPolicy, "codecPolicy"); } /** - * Sets the decoding behavior when the input bytes contain leftover trailing bits that - * cannot be created by a valid encoding. These can be bits that are unused from the final - * character or entire characters. The default mode is lenient decoding. Set this to - * {@code true} to enable strict decoding. - * <ul> - * <li>Lenient: Any trailing bits are composed into 8-bit bytes where possible. - * The remainder are discarded. - * <li>Strict: The decoding will raise an {@link IllegalArgumentException} if trailing bits - * are not part of a valid encoding. Any unused bits from the final character must - * be zero. Impossible counts of entire final characters are not allowed. - * </ul> + * Returns true if decoding behavior is strict. Decoding will raise an {@link IllegalArgumentException} if trailing + * bits are not part of a valid encoding. * - * <p>When strict decoding is enabled it is expected that the decoded bytes will be re-encoded - * to a byte array that matches the original, i.e. no changes occur on the final - * character. This requires that the input bytes use the same padding and alphabet - * as the encoder. + * <p> + * The default is false for lenient encoding. Decoding will compose trailing bits into 8-bit bytes and discard the + * remainder. + * </p> * - * @param strictDecoding Set to true to enable strict decoding; otherwise use lenient decoding. - * @see #encode(byte[]) + * @return true if using strict decoding * @since 1.15 */ - public void setStrictDecoding(boolean strictDecoding) { - this.strictDecoding = strictDecoding; + public boolean isStrictDecoding() { + return decodingPolicy == CodecPolicy.STRICT; } /** - * Returns true if decoding behavior is strict. Decoding will raise an - * {@link IllegalArgumentException} if trailing bits are not part of a valid encoding. + * Returns the decoding behavior policy. Decoding will raise an {@link IllegalArgumentException} if trailing bits + * are not part of a valid encoding. * - * <p>The default is false for lenient encoding. Decoding will compose trailing bits - * into 8-bit bytes and discard the remainder. + * <p> + * The default is lenient. Decoding will compose trailing bits into 8-bit bytes and discard the remainder. + * </p> * * @return true if using strict decoding - * @see #setStrictDecoding(boolean) * @since 1.15 */ - public boolean isStrictDecoding() { - return strictDecoding; + public CodecPolicy getCodecPolicy() { + return decodingPolicy; } /** @@ -418,6 +466,17 @@ public abstract class BaseNCodec implements BinaryEncoder, BinaryDecoder { } /** + * Gets a copy of the chunk separator per RFC 2045 section 2.1. + * + * @return the chunk separator + * @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a> + * @since 1.15 + */ + public static byte[] getChunkSeparator() { + return CHUNK_SEPARATOR.clone(); + } + + /** * Checks if a byte value is whitespace or not. * Whitespace is taken to mean: space, tab, CR, LF * @param byteToCheck diff --git a/src/main/java/org/apache/commons/codec/binary/BaseNCodecInputStream.java b/src/main/java/org/apache/commons/codec/binary/BaseNCodecInputStream.java index c183c43..90792f1 100644 --- a/src/main/java/org/apache/commons/codec/binary/BaseNCodecInputStream.java +++ b/src/main/java/org/apache/commons/codec/binary/BaseNCodecInputStream.java @@ -48,25 +48,6 @@ public class BaseNCodecInputStream extends FilterInputStream { } /** - * Sets the decoding behavior when the input bytes contain leftover trailing bits that - * cannot be created by a valid encoding. This setting is transferred to the instance - * of {@link BaseNCodec} used to perform decoding. - * - * <p>The default is false for lenient encoding. Decoding will compose trailing bits - * into 8-bit bytes and discard the remainder. - * - * <p>Set to true to enable strict decoding. Decoding will raise an - * {@link IllegalArgumentException} if trailing bits are not part of a valid encoding. - * - * @param strictDecoding Set to true to enable strict decoding; otherwise use lenient decoding. - * @see BaseNCodec#setStrictDecoding(boolean) - * @since 1.15 - */ - public void setStrictDecoding(boolean strictDecoding) { - baseNCodec.setStrictDecoding(strictDecoding); - } - - /** * Returns true if decoding behavior is strict. Decoding will raise an * {@link IllegalArgumentException} if trailing bits are not part of a valid encoding. * @@ -74,7 +55,6 @@ public class BaseNCodecInputStream extends FilterInputStream { * into 8-bit bytes and discard the remainder. * * @return true if using strict decoding - * @see #setStrictDecoding(boolean) * @since 1.15 */ public boolean isStrictDecoding() { diff --git a/src/main/java/org/apache/commons/codec/binary/BaseNCodecOutputStream.java b/src/main/java/org/apache/commons/codec/binary/BaseNCodecOutputStream.java index 71b2a13..bc27e07 100644 --- a/src/main/java/org/apache/commons/codec/binary/BaseNCodecOutputStream.java +++ b/src/main/java/org/apache/commons/codec/binary/BaseNCodecOutputStream.java @@ -61,25 +61,6 @@ public class BaseNCodecOutputStream extends FilterOutputStream { } /** - * Sets the decoding behavior when the input bytes contain leftover trailing bits that - * cannot be created by a valid encoding. This setting is transferred to the instance - * of {@link BaseNCodec} used to perform decoding. - * - * <p>The default is false for lenient encoding. Decoding will compose trailing bits - * into 8-bit bytes and discard the remainder. - * - * <p>Set to true to enable strict decoding. Decoding will raise an - * {@link IllegalArgumentException} if trailing bits are not part of a valid encoding. - * - * @param strictDecoding Set to true to enable strict decoding; otherwise use lenient decoding. - * @see BaseNCodec#setStrictDecoding(boolean) - * @since 1.15 - */ - public void setStrictDecoding(boolean strictDecoding) { - baseNCodec.setStrictDecoding(strictDecoding); - } - - /** * Returns true if decoding behavior is strict. Decoding will raise an * {@link IllegalArgumentException} if trailing bits are not part of a valid encoding. * @@ -87,7 +68,6 @@ public class BaseNCodecOutputStream extends FilterOutputStream { * into 8-bit bytes and discard the remainder. * * @return true if using strict decoding - * @see #setStrictDecoding(boolean) * @since 1.15 */ public boolean isStrictDecoding() { diff --git a/src/main/java/org/apache/commons/codec/net/BCodec.java b/src/main/java/org/apache/commons/codec/net/BCodec.java index b054e3b..e9f9ecc 100644 --- a/src/main/java/org/apache/commons/codec/net/BCodec.java +++ b/src/main/java/org/apache/commons/codec/net/BCodec.java @@ -21,11 +21,13 @@ import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import org.apache.commons.codec.CodecPolicy; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.EncoderException; import org.apache.commons.codec.StringDecoder; import org.apache.commons.codec.StringEncoder; import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.binary.BaseNCodec; /** * Identical to the Base64 encoding defined by <a href="http://www.ietf.org/rfc/rfc1521.txt">RFC 1521</a> @@ -43,6 +45,12 @@ import org.apache.commons.codec.binary.Base64; * @since 1.3 */ public class BCodec extends RFC1522Codec implements StringEncoder, StringDecoder { + + /** + * The default decoding policy. + */ + private static final CodecPolicy DECODING_POLICY_DEFAULT = CodecPolicy.LENIENT; + /** * The default Charset used for string decoding and encoding. */ @@ -52,7 +60,7 @@ public class BCodec extends RFC1522Codec implements StringEncoder, StringDecoder * If true then decoding should throw an exception for impossible combinations of bits at the * end of the byte input. The default is to decode as much of them as possible. */ - private boolean strictDecoding; + private final CodecPolicy decodingPolicy; /** * Default constructor. @@ -72,6 +80,22 @@ public class BCodec extends RFC1522Codec implements StringEncoder, StringDecoder */ public BCodec(final Charset charset) { this.charset = charset; + this.decodingPolicy = DECODING_POLICY_DEFAULT; + } + + /** + * Constructor which allows for the selection of a default Charset. + * + * @param charset + * the default string Charset to use. + * @param decodingPolicy The decoding policy. + * + * @see <a href="http://download.oracle.com/javase/7/docs/api/java/nio/charset/Charset.html">Standard charsets</a> + * @since 1.15 + */ + public BCodec(final Charset charset, final CodecPolicy decodingPolicy) { + this.charset = charset; + this.decodingPolicy = decodingPolicy; } /** @@ -89,25 +113,6 @@ public class BCodec extends RFC1522Codec implements StringEncoder, StringDecoder } /** - * Sets the decoding behavior when the input bytes contain leftover trailing bits that - * cannot be created by a valid Base64 encoding. This setting is transferred to the instance - * of {@link Base64} used to perform decoding. - * - * <p>The default is false for lenient encoding. Decoding will compose trailing bits - * into 8-bit bytes and discard the remainder. - * - * <p>Set to true to enable strict decoding. Decoding will raise a - * {@link DecoderException} if trailing bits are not part of a valid Base64 encoding. - * - * @param strictDecoding Set to true to enable strict decoding; otherwise use lenient decoding. - * @see org.apache.commons.codec.binary.BaseNCodec#setStrictDecoding(boolean) BaseNCodec.setStrictDecoding(boolean) - * @since 1.15 - */ - public void setStrictDecoding(boolean strictDecoding) { - this.strictDecoding = strictDecoding; - } - - /** * Returns true if decoding behavior is strict. Decoding will raise a * {@link DecoderException} if trailing bits are not part of a valid Base64 encoding. * @@ -115,11 +120,10 @@ public class BCodec extends RFC1522Codec implements StringEncoder, StringDecoder * into 8-bit bytes and discard the remainder. * * @return true if using strict decoding - * @see #setStrictDecoding(boolean) * @since 1.15 */ public boolean isStrictDecoding() { - return strictDecoding; + return decodingPolicy == CodecPolicy.STRICT; } @Override @@ -140,9 +144,7 @@ public class BCodec extends RFC1522Codec implements StringEncoder, StringDecoder if (bytes == null) { return null; } - final Base64 codec = new Base64(); - codec.setStrictDecoding(strictDecoding); - return codec.decode(bytes); + return new Base64(0, BaseNCodec.getChunkSeparator(), false, decodingPolicy).decode(bytes); } /** diff --git a/src/test/java/org/apache/commons/codec/binary/Base32InputStreamTest.java b/src/test/java/org/apache/commons/codec/binary/Base32InputStreamTest.java index 85bcbb3..fe77eee 100644 --- a/src/test/java/org/apache/commons/codec/binary/Base32InputStreamTest.java +++ b/src/test/java/org/apache/commons/codec/binary/Base32InputStreamTest.java @@ -29,6 +29,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.Arrays; +import org.apache.commons.codec.CodecPolicy; import org.junit.Test; public class Base32InputStreamTest { @@ -574,8 +575,7 @@ public class Base32InputStreamTest { Base32TestData.streamToBytes(in); // Strict decoding should throw - in = new Base32InputStream(new ByteArrayInputStream(encoded), false); - in.setStrictDecoding(true); + in = new Base32InputStream(new ByteArrayInputStream(encoded), false, 0, null, CodecPolicy.STRICT); assertTrue(in.isStrictDecoding()); try { Base32TestData.streamToBytes(in); diff --git a/src/test/java/org/apache/commons/codec/binary/Base32OutputStreamTest.java b/src/test/java/org/apache/commons/codec/binary/Base32OutputStreamTest.java index 2cb09e0..a276f8e 100644 --- a/src/test/java/org/apache/commons/codec/binary/Base32OutputStreamTest.java +++ b/src/test/java/org/apache/commons/codec/binary/Base32OutputStreamTest.java @@ -25,11 +25,12 @@ import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.util.Arrays; +import org.apache.commons.codec.CodecPolicy; import org.junit.Test; public class Base32OutputStreamTest { - private final static byte[] CRLF = {(byte) '\r', (byte) '\n'}; + private final static byte[] CR_LF = {(byte) '\r', (byte) '\n'}; private final static byte[] LF = {(byte) '\n'}; @@ -84,8 +85,8 @@ public class Base32OutputStreamTest { private void testBase32EmptyOutputStream(final int chunkSize) throws Exception { final byte[] emptyEncoded = new byte[0]; final byte[] emptyDecoded = new byte[0]; - testByteByByte(emptyEncoded, emptyDecoded, chunkSize, CRLF); - testByChunk(emptyEncoded, emptyDecoded, chunkSize, CRLF); + testByteByByte(emptyEncoded, emptyDecoded, chunkSize, CR_LF); + testByChunk(emptyEncoded, emptyDecoded, chunkSize, CR_LF); } /** @@ -99,7 +100,7 @@ public class Base32OutputStreamTest { // Hello World test. byte[] encoded = StringUtils.getBytesUtf8(Base32TestData.BASE32_FIXTURE); byte[] decoded = StringUtils.getBytesUtf8(Base32TestData.STRING_FIXTURE); - testByChunk(encoded, decoded, BaseNCodec.MIME_CHUNK_SIZE, CRLF); + testByChunk(encoded, decoded, BaseNCodec.MIME_CHUNK_SIZE, CR_LF); // // Single Byte test. // encoded = StringUtils.getBytesUtf8("AA==\r\n"); @@ -134,7 +135,7 @@ public class Base32OutputStreamTest { // Hello World test. byte[] encoded = StringUtils.getBytesUtf8(Base32TestData.BASE32_FIXTURE); byte[] decoded = StringUtils.getBytesUtf8(Base32TestData.STRING_FIXTURE); - testByteByByte(encoded, decoded, 76, CRLF); + testByteByByte(encoded, decoded, 76, CR_LF); // // Single Byte test. // encoded = StringUtils.getBytesUtf8("AA==\r\n"); @@ -354,8 +355,7 @@ public class Base32OutputStreamTest { // Strict decoding should throw bout = new ByteArrayOutputStream(); - out = new Base32OutputStream(bout, false); - out.setStrictDecoding(true); + out = new Base32OutputStream(bout, false, 0, null, CodecPolicy.STRICT); assertTrue(out.isStrictDecoding()); try { out.write(encoded); diff --git a/src/test/java/org/apache/commons/codec/binary/Base32Test.java b/src/test/java/org/apache/commons/codec/binary/Base32Test.java index 7033e91..65c828e 100644 --- a/src/test/java/org/apache/commons/codec/binary/Base32Test.java +++ b/src/test/java/org/apache/commons/codec/binary/Base32Test.java @@ -18,9 +18,9 @@ package org.apache.commons.codec.binary; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -29,6 +29,7 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Arrays; +import org.apache.commons.codec.CodecPolicy; import org.apache.commons.codec.DecoderException; import org.apache.commons.lang3.ArrayUtils; import org.junit.Test; @@ -291,21 +292,24 @@ public class Base32Test { @Test public void testBase32ImpossibleSamples() { - testImpossibleCases(new Base32(), BASE32_IMPOSSIBLE_CASES); + testImpossibleCases(new Base32(0, null, false, BaseNCodec.PAD_DEFAULT, CodecPolicy.STRICT), + BASE32_IMPOSSIBLE_CASES); } @Test public void testBase32ImpossibleChunked() { - testImpossibleCases(new Base32(20), BASE32_IMPOSSIBLE_CASES_CHUNKED); + testImpossibleCases( + new Base32(20, BaseNCodec.CHUNK_SEPARATOR, false, BaseNCodec.PAD_DEFAULT, CodecPolicy.STRICT), + BASE32_IMPOSSIBLE_CASES_CHUNKED); } @Test public void testBase32HexImpossibleSamples() { - testImpossibleCases(new Base32(true), BASE32HEX_IMPOSSIBLE_CASES); + testImpossibleCases(new Base32(0, null, true, BaseNCodec.PAD_DEFAULT, CodecPolicy.STRICT), + BASE32HEX_IMPOSSIBLE_CASES); } private void testImpossibleCases(final Base32 codec, final String[] impossible_cases) { - codec.setStrictDecoding(true); for (final String impossible : impossible_cases) { try { codec.decode(impossible); @@ -360,9 +364,8 @@ public class Base32Test { * @param nbits the number of trailing bits (must be a factor of 5 and {@code <40}) */ private static void assertBase32DecodingOfTrailingBits(final int nbits) { - final Base32 codec = new Base32(); // Requires strict decoding - codec.setStrictDecoding(true); + final Base32 codec = new Base32(0, null, false, BaseNCodec.PAD_DEFAULT, CodecPolicy.STRICT); assertTrue(codec.isStrictDecoding()); // A lenient decoder should not re-encode to the same bytes final Base32 defaultCodec = new Base32(); diff --git a/src/test/java/org/apache/commons/codec/binary/Base64InputStreamTest.java b/src/test/java/org/apache/commons/codec/binary/Base64InputStreamTest.java index 2b1f5cf..83a0285 100644 --- a/src/test/java/org/apache/commons/codec/binary/Base64InputStreamTest.java +++ b/src/test/java/org/apache/commons/codec/binary/Base64InputStreamTest.java @@ -32,6 +32,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.Arrays; +import org.apache.commons.codec.CodecPolicy; import org.junit.Test; /** @@ -587,8 +588,7 @@ public class Base64InputStreamTest { Base64TestData.streamToBytes(in); // Strict decoding should throw - in = new Base64InputStream(new ByteArrayInputStream(encoded), false); - in.setStrictDecoding(true); + in = new Base64InputStream(new ByteArrayInputStream(encoded), false, 0, null, CodecPolicy.STRICT); assertTrue(in.isStrictDecoding()); try { Base64TestData.streamToBytes(in); diff --git a/src/test/java/org/apache/commons/codec/binary/Base64OutputStreamTest.java b/src/test/java/org/apache/commons/codec/binary/Base64OutputStreamTest.java index b644363..a2e3157 100644 --- a/src/test/java/org/apache/commons/codec/binary/Base64OutputStreamTest.java +++ b/src/test/java/org/apache/commons/codec/binary/Base64OutputStreamTest.java @@ -26,6 +26,7 @@ import java.io.ByteArrayOutputStream; import java.io.OutputStream; import java.util.Arrays; +import org.apache.commons.codec.CodecPolicy; import org.junit.Test; /** @@ -33,7 +34,7 @@ import org.junit.Test; */ public class Base64OutputStreamTest { - private final static byte[] CRLF = {(byte) '\r', (byte) '\n'}; + private final static byte[] CR_LF = {(byte) '\r', (byte) '\n'}; private final static byte[] LF = {(byte) '\n'}; @@ -86,8 +87,8 @@ public class Base64OutputStreamTest { private void testBase64EmptyOutputStream(final int chunkSize) throws Exception { final byte[] emptyEncoded = new byte[0]; final byte[] emptyDecoded = new byte[0]; - testByteByByte(emptyEncoded, emptyDecoded, chunkSize, CRLF); - testByChunk(emptyEncoded, emptyDecoded, chunkSize, CRLF); + testByteByByte(emptyEncoded, emptyDecoded, chunkSize, CR_LF); + testByChunk(emptyEncoded, emptyDecoded, chunkSize, CR_LF); } /** @@ -101,12 +102,12 @@ public class Base64OutputStreamTest { // Hello World test. byte[] encoded = StringUtils.getBytesUtf8("SGVsbG8gV29ybGQ=\r\n"); byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE); - testByChunk(encoded, decoded, BaseNCodec.MIME_CHUNK_SIZE, CRLF); + testByChunk(encoded, decoded, BaseNCodec.MIME_CHUNK_SIZE, CR_LF); // Single Byte test. encoded = StringUtils.getBytesUtf8("AA==\r\n"); decoded = new byte[]{(byte) 0}; - testByChunk(encoded, decoded, BaseNCodec.MIME_CHUNK_SIZE, CRLF); + testByChunk(encoded, decoded, BaseNCodec.MIME_CHUNK_SIZE, CR_LF); // OpenSSL interop test. encoded = StringUtils.getBytesUtf8(Base64TestData.ENCODED_64_CHARS_PER_LINE); @@ -139,12 +140,12 @@ public class Base64OutputStreamTest { // Hello World test. byte[] encoded = StringUtils.getBytesUtf8("SGVsbG8gV29ybGQ=\r\n"); byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE); - testByteByByte(encoded, decoded, 76, CRLF); + testByteByByte(encoded, decoded, 76, CR_LF); // Single Byte test. encoded = StringUtils.getBytesUtf8("AA==\r\n"); decoded = new byte[]{(byte) 0}; - testByteByByte(encoded, decoded, 76, CRLF); + testByteByByte(encoded, decoded, 76, CR_LF); // OpenSSL interop test. encoded = StringUtils.getBytesUtf8(Base64TestData.ENCODED_64_CHARS_PER_LINE); @@ -362,8 +363,7 @@ public class Base64OutputStreamTest { // Strict decoding should throw bout = new ByteArrayOutputStream(); - out = new Base64OutputStream(bout, false); - out.setStrictDecoding(true); + out = new Base64OutputStream(bout, false, 0, null, CodecPolicy.STRICT); assertTrue(out.isStrictDecoding()); try { out.write(encoded); diff --git a/src/test/java/org/apache/commons/codec/binary/Base64Test.java b/src/test/java/org/apache/commons/codec/binary/Base64Test.java index 8d79f59..884b4a2 100644 --- a/src/test/java/org/apache/commons/codec/binary/Base64Test.java +++ b/src/test/java/org/apache/commons/codec/binary/Base64Test.java @@ -30,6 +30,7 @@ import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Random; +import org.apache.commons.codec.CodecPolicy; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.EncoderException; import org.apache.commons.lang3.ArrayUtils; @@ -1323,8 +1324,7 @@ public class Base64Test { @Test public void testBase64ImpossibleSamples() { - final Base64 codec = new Base64(); - codec.setStrictDecoding(true); + final Base64 codec = new Base64(0, null, false, CodecPolicy.STRICT); for (final String s : BASE64_IMPOSSIBLE_CASES) { try { codec.decode(s); @@ -1359,9 +1359,8 @@ public class Base64Test { * @param nbits the number of trailing bits (must be a factor of 6 and {@code <24}) */ private static void assertBase64DecodingOfTrailingBits(final int nbits) { - final Base64 codec = new Base64(); + final Base64 codec = new Base64(0, null, false, CodecPolicy.STRICT); // Requires strict decoding - codec.setStrictDecoding(true); assertTrue(codec.isStrictDecoding()); // A lenient decoder should not re-encode to the same bytes final Base64 defaultCodec = new Base64(); diff --git a/src/test/java/org/apache/commons/codec/net/BCodecTest.java b/src/test/java/org/apache/commons/codec/net/BCodecTest.java index 4569e41..45392a3 100644 --- a/src/test/java/org/apache/commons/codec/net/BCodecTest.java +++ b/src/test/java/org/apache/commons/codec/net/BCodecTest.java @@ -21,9 +21,11 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; +import java.nio.charset.StandardCharsets; import java.nio.charset.UnsupportedCharsetException; import org.apache.commons.codec.CharEncoding; +import org.apache.commons.codec.CodecPolicy; import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.EncoderException; import org.junit.Assert; @@ -158,15 +160,28 @@ public class BCodecTest { } @Test - public void testBase64ImpossibleSamples() throws DecoderException { + public void testBase64ImpossibleSamplesDefault() throws DecoderException { final BCodec codec = new BCodec(); // Default encoding is lenient Assert.assertFalse(codec.isStrictDecoding()); for (final String s : BASE64_IMPOSSIBLE_CASES) { codec.decode(s); } - // Use strict mode to prevent impossible cases - codec.setStrictDecoding(true); + } + + @Test + public void testBase64ImpossibleSamplesLenient() throws DecoderException { + final BCodec codec = new BCodec(StandardCharsets.UTF_8, CodecPolicy.LENIENT); + // Default encoding is lenient + Assert.assertFalse(codec.isStrictDecoding()); + for (final String s : BASE64_IMPOSSIBLE_CASES) { + codec.decode(s); + } + } + + @Test + public void testBase64ImpossibleSamplesStrict() throws DecoderException { + final BCodec codec = new BCodec(StandardCharsets.UTF_8, CodecPolicy.STRICT); Assert.assertTrue(codec.isStrictDecoding()); for (final String s : BASE64_IMPOSSIBLE_CASES) { try { @@ -177,4 +192,5 @@ public class BCodecTest { } } } + }