On Sun, May 17, 2020 at 3:46 PM Alex Herbert <alex.d.herb...@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 , <ggreg...@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 <garydgreg...@gmail.com>
> > AuthorDate: Sun May 17 11:51:25 2020 -0400
> >
> >     Reimplement the new-in-1.15 BaseNCodec's and friends' strict vs.
> > lenient
> >     decoding as final instance variables and with an enum instead of a
> >     boolean. Introduce the last amount of new constructors.
> > ---
> >  .../java/org/apache/commons/codec/CodecPolicy.java |  36 +++++++
> >  .../org/apache/commons/codec/binary/Base32.java    |  60 +++++++----
> >  .../commons/codec/binary/Base32InputStream.java    |  43 +++++++-
> >  .../commons/codec/binary/Base32OutputStream.java   |  42 +++++++-
> >  .../org/apache/commons/codec/binary/Base64.java    |  56 +++++++---
> >  .../commons/codec/binary/Base64InputStream.java    |  42 +++++++-
> >  .../commons/codec/binary/Base64OutputStream.java   |  42 +++++++-
> >  .../apache/commons/codec/binary/BaseNCodec.java    | 119
> > +++++++++++++++------
> >  .../codec/binary/BaseNCodecInputStream.java        |  20 ----
> >  .../codec/binary/BaseNCodecOutputStream.java       |  20 ----
> >  .../java/org/apache/commons/codec/net/BCodec.java  |  52 ++++-----
> >  .../codec/binary/Base32InputStreamTest.java        |   4 +-
> >  .../codec/binary/Base32OutputStreamTest.java       |  14 +--
> >  .../apache/commons/codec/binary/Base32Test.java    |  17 +--
> >  .../codec/binary/Base64InputStreamTest.java        |   4 +-
> >  .../codec/binary/Base64OutputStreamTest.java       |  18 ++--
> >  .../apache/commons/codec/binary/Base64Test.java    |   7 +-
> >  .../org/apache/commons/codec/net/BCodecTest.java   |  22 +++-
> >  18 files changed, 451 insertions(+), 167 deletions(-)
> >
> > diff --git a/src/main/java/org/apache/commons/codec/CodecPolicy.java
> > b/src/main/java/org/apache/commons/codec/CodecPolicy.java
> > new file mode 100644
> > index 0000000..9cf5e12
> > --- /dev/null
> > +++ b/src/main/java/org/apache/commons/codec/CodecPolicy.java
> > @@ -0,0 +1,36 @@
> > +/*
> > + * Licensed to the Apache Software Foundation (ASF) under one or more
> > + * contributor license agreements.  See the NOTICE file distributed with
> > + * this work for additional information regarding copyright ownership.
> > + * The ASF licenses this file to You under the Apache License, Version
> 2.0
> > + * (the "License"); you may not use this file except in compliance with
> > + * the License.  You may obtain a copy of the License at
> > + *
> > + *      http://www.apache.org/licenses/LICENSE-2.0
> > + *
> > + * Unless required by applicable law or agreed to in writing, software
> > + * distributed under the License is distributed on an "AS IS" BASIS,
> > + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> > implied.
> > + * See the License for the specific language governing permissions and
> > + * limitations under the License.
> > + */
> > +
> > +package org.apache.commons.codec;
> > +
> > +/**
> > + * Defines encoding and decoding policies.
> > + *
> > + * @since 1.15
> > + */
> > +public enum CodecPolicy {
> > +
> > +    /**
> > +     * The strict policy. Data that causes a codec to fail should throw
> > an exception.
> > +     */
> > +    STRICT,
> > +
> > +    /**
> > +     * The strict policy. Data that causes a codec to fail should not
> > throw an exception.
> > +     */
> > +    LENIENT
> > +}
> > diff --git a/src/main/java/org/apache/commons/codec/binary/Base32.java
> > b/src/main/java/org/apache/commons/codec/binary/Base32.java
> > index aa5d3e4..8d57861 100644
> > --- a/src/main/java/org/apache/commons/codec/binary/Base32.java
> > +++ b/src/main/java/org/apache/commons/codec/binary/Base32.java
> > @@ -17,6 +17,8 @@
> >
> >  package org.apache.commons.codec.binary;
> >
> > +import org.apache.commons.codec.CodecPolicy;
> > +
> >  /**
> >   * Provides Base32 encoding and decoding as defined by <a href="
> > http://www.ietf.org/rfc/rfc4648.txt";>RFC 4648</a>.
> >   *
> > @@ -52,13 +54,6 @@ public class Base32 extends BaseNCodec {
> >      private static final int BYTES_PER_UNENCODED_BLOCK = 5;
> >
> >      /**
> > -     * Chunk separator per RFC 2045 section 2.1.
> > -     *
> > -     * @see <a href="http://www.ietf.org/rfc/rfc2045.txt";>RFC 2045
> > section 2.1</a>
> > -     */
> > -    private static final byte[] CHUNK_SEPARATOR = {'\r', '\n'};
> > -
> > -    /**
> >       * This array is a lookup table that translates Unicode characters
> > drawn from the "Base32 Alphabet" (as specified
> >       * in Table 3 of RFC 4648) into their 5-bit positive integer
> > equivalents. Characters that are not in the Base32
> >       * alphabet but fall within the bounds of the array are translated
> to
> > -1.
> > @@ -200,10 +195,10 @@ public class Base32 extends BaseNCodec {
> >       * When encoding the line length is 0 (no chunking).
> >       * </p>
> >       * @param useHex if {@code true} then use Base32 Hex alphabet
> > -     * @param pad byte used as padding byte.
> > +     * @param padding byte used as padding byte.
> >       */
> > -    public Base32(final boolean useHex, final byte pad) {
> > -        this(0, null, useHex, pad);
> > +    public Base32(final boolean useHex, final byte padding) {
> > +        this(0, null, useHex, padding);
> >      }
> >
> >      /**
> > @@ -237,7 +232,7 @@ public class Base32 extends BaseNCodec {
> >       * @param lineSeparator
> >       *            Each line of encoded data will end with this sequence
> > of bytes.
> >       * @throws IllegalArgumentException
> > -     *             The provided lineSeparator included some Base32
> > characters. That's not going to work!
> > +     *             Thrown when the {@code lineSeparator} contains Base32
> > characters.
> >       */
> >      public Base32(final int lineLength, final byte[] lineSeparator) {
> >          this(lineLength, lineSeparator, false, PAD_DEFAULT);
> > @@ -261,7 +256,7 @@ public class Base32 extends BaseNCodec {
> >       * @param useHex
> >       *            if {@code true}, then use Base32 Hex alphabet,
> > otherwise use Base32 alphabet
> >       * @throws IllegalArgumentException
> > -     *             The provided lineSeparator included some Base32
> > characters. That's not going to work! Or the
> > +     *             Thrown when the {@code lineSeparator} contains Base32
> > characters. Or the
> >       *             lineLength &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 {
> >              }
> >          }
> >      }
> > +
> >  }
> >
> >
>

Reply via email to