You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by Alex Herbert <al...@gmail.com> on 2020/05/17 19:46:25 UTC

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.

+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 {
>              }
>          }
>      }
> +
>  }
>
>

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 {
> >              }
> >          }
> >      }
> > +
> >  }
> >
> >
>