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 2020/05/17 15:51:31 UTC

[commons-codec] branch master updated: 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.

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 <ga...@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 &gt; 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 &gt; 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 &lt;= 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 &gt; 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 &lt;= 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 &lt;= 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 &lt;= 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 &lt;= 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 &lt;= 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 &lt;= 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 &lt;= 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 &lt;= 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 &lt;= 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 &gt; 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 {
             }
         }
     }
+
 }


Re: [commons-codec] branch master updated: 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.

Posted by Gary Gregory <ga...@gmail.com>.
On Sun, May 17, 2020 at 3:46 PM Alex Herbert <al...@gmail.com>
wrote:

> +1 to the changes.
>
> One minor nit is the javadoc on line 307 of BaseNCodec.getCodecPolicy which
> states that decoding will raise an exception. This should be qualified by
> stating it will raise an exception when in strict decoding mode. I think
> the sentence about the default mode should be first. Then the sentence
> about strict decoding, i.e. the alternative, raising an exception.
>

I updated org.apache.commons.codec.binary.BaseNCodec.getCodecPolicy()


>
> A second nit is line 295 of BaseNCodec.isStrictDecoding that states the
> default is for lenient *encoding*. This should be *decoding*.
>

I updated org.apache.commons.codec.binary.BaseNCodec.isStrictDecoding()


>
> One issue is whether decoding should raise a DecoderException and not an
> IllegalArgumentException.
>

Will ponder...

Gary


>
> WDYT?
>
> Alex
>
>
> On Sun, 17 May 2020, 16:51 , <gg...@apache.org> wrote:
>
> > 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 <ga...@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 &gt; 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 &gt; 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 &lt;= 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 &gt; 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 &lt;= 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 &lt;= 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 &lt;= 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 &lt;= 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 &lt;= 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 &lt;= 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 &lt;= 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 &lt;= 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 &lt;= 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 &gt; 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 {
> >              }
> >          }
> >      }
> > +
> >  }
> >
> >
>

Re: [commons-codec] branch master updated: 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.

Posted by Alex Herbert <al...@gmail.com>.
+1 to the changes.

One minor nit is the javadoc on line 307 of BaseNCodec.getCodecPolicy which
states that decoding will raise an exception. This should be qualified by
stating it will raise an exception when in strict decoding mode. I think
the sentence about the default mode should be first. Then the sentence
about strict decoding, i.e. the alternative, raising an exception.

A second nit is line 295 of BaseNCodec.isStrictDecoding that states the
default is for lenient *encoding*. This should be *decoding*.

One issue is whether decoding should raise a DecoderException and not an
IllegalArgumentException.

WDYT?

Alex


On Sun, 17 May 2020, 16:51 , <gg...@apache.org> wrote:

> 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 <ga...@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 &gt; 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 &gt; 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 &lt;= 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 &gt; 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 &lt;= 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 &lt;= 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 &lt;= 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 &lt;= 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 &lt;= 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 &lt;= 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 &lt;= 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 &lt;= 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 &lt;= 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 &gt; 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 {
>              }
>          }
>      }
> +
>  }
>
>