This is an automated email from the ASF dual-hosted git repository.

aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-codec.git

commit 019ee2c989d21bb5de8e26a12bbf87f2f870fa7e
Author: Adam Retter <adam.ret...@googlemail.com>
AuthorDate: Sun May 31 23:46:05 2020 +0200

    Refactored to use a Lookup Table
---
 .../org/apache/commons/codec/binary/Base16.java    | 312 ++++++-------
 .../commons/codec/binary/Base16InputStream.java    |  26 +-
 .../commons/codec/binary/Base16OutputStream.java   |  26 +-
 .../codec/binary/Base16InputStreamTest.java        | 155 ++++---
 .../codec/binary/Base16OutputStreamTest.java       | 169 +++----
 .../apache/commons/codec/binary/Base16Test.java    | 485 ++++++++++-----------
 6 files changed, 586 insertions(+), 587 deletions(-)

diff --git a/src/main/java/org/apache/commons/codec/binary/Base16.java 
b/src/main/java/org/apache/commons/codec/binary/Base16.java
index 1732f69..eb875cb 100644
--- a/src/main/java/org/apache/commons/codec/binary/Base16.java
+++ b/src/main/java/org/apache/commons/codec/binary/Base16.java
@@ -18,9 +18,6 @@
 package org.apache.commons.codec.binary;
 
 import org.apache.commons.codec.CodecPolicy;
-import org.apache.commons.codec.DecoderException;
-
-import java.nio.charset.Charset;
 
 /**
  * Provides Base16 encoding and decoding.
@@ -29,79 +26,118 @@ import java.nio.charset.Charset;
  * This class is thread-safe.
  * </p>
  *
+ * @see <a href="https://tools.ietf.org/html/rfc4648#section-8";>RFC 4648 - 8. 
Base 16 Encoding</a>
+ *
  * @since 1.15
  */
 public class Base16 extends BaseNCodec {
 
-    private static final int BYTES_PER_UNENCODED_BLOCK = 1;
+    /**
+     * BASE16 characters are 4 bits in length.
+     * They are formed by taking an 8-bit group,
+     * which is converted into two BASE16 characters.
+     */
+    private static final int BITS_PER_ENCODED_BYTE = 4;
     private static final int BYTES_PER_ENCODED_BLOCK = 2;
+    private static final int BYTES_PER_UNENCODED_BLOCK = 1;
+
+    /**
+     * This array is a lookup table that translates Unicode characters drawn 
from the "Base16 Alphabet" (as specified
+     * in Table 5 of RFC 4648) into their 4-bit positive integer equivalents. 
Characters that are not in the Base16
+     * alphabet but fall within the bounds of the array are translated to -1.
+     */
+    private static final byte[] UPPER_CASE_DECODE_TABLE = {
+            //  0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 
00-0f
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 
10-1f
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 
20-2f
+             0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1, // 
30-3f 0-9
+            -1, 10, 11, 12, 13, 14, 15                                      // 
40-46 A-F
+    };
 
-    private final boolean toLowerCase;
-    private final Charset charset;
+    /**
+     * This array is a lookup table that translates 4-bit positive integer 
index values into their "Base16 Alphabet"
+     * equivalents as specified in Table 5 of RFC 4648.
+     */
+    private static final byte[] UPPER_CASE_ENCODE_TABLE = {
+            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+            'A', 'B', 'C', 'D', 'E', 'F'
+    };
 
     /**
-     * Creates a Base16 codec used for decoding and encoding.
+     * This array is a lookup table that translates Unicode characters drawn 
from the a lower-case "Base16 Alphabet"
+     * into their 4-bit positive integer equivalents. Characters that are not 
in the Base16
+     * alphabet but fall within the bounds of the array are translated to -1.
      */
-    protected Base16() {
-        this(Hex.DEFAULT_CHARSET);
-    }
+    private static final byte[] LOWER_CASE_DECODE_TABLE = {
+            //  0   1   2   3   4   5   6   7   8   9   A   B   C   D   E   F
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 
00-0f
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 
10-1f
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 
20-2f
+             0,  1,  2,  3,  4,  5,  6,  7,  8,  9, -1, -1, -1, -1, -1, -1, // 
30-3f 0-9
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 
40-4f
+            -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 
50-5f
+            -1, 10, 11, 12, 13, 14, 15                                      // 
60-66 a-f
+    };
+
+    /**
+     * This array is a lookup table that translates 4-bit positive integer 
index values into their "Base16 Alphabet"
+     * lower-case equivalents.
+     */
+    private static final byte[] LOWER_CASE_ENCODE_TABLE = {
+            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+            'a', 'b', 'c', 'd', 'e', 'f'
+    };
+
+    /** Mask used to extract 4 bits, used when decoding character. */
+    private static final int MASK_4BITS = 0x0f;
+
+    /**
+     * Decode table to use.
+     */
+    private final byte[] decodeTable;
+
+    /**
+     * Encode table to use.
+     */
+    private final byte[] encodeTable;
 
     /**
      * Creates a Base16 codec used for decoding and encoding.
-     *
-     * @param charset the charset.
      */
-    protected Base16(final Charset charset) {
-        this(true, charset);
+    public Base16() {
+        this(false);
     }
 
     /**
      * Creates a Base16 codec used for decoding and encoding.
      *
-     * @param toLowerCase {@code true} converts to lowercase, {@code false} to 
uppercase.
-     * @param charset the charset.
+     * @param lowerCase if {@code true} then use a lower-case Base16 alphabet.
      */
-    protected Base16(final boolean toLowerCase, final Charset charset) {
-        super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, 0, 0);
-        this.toLowerCase = toLowerCase;
-        this.charset = charset;
+    public Base16(final boolean lowerCase) {
+        this(lowerCase, DECODING_POLICY_DEFAULT);
     }
 
     /**
      * Creates a Base16 codec used for decoding and encoding.
      *
-     * @param toLowerCase {@code true} converts to lowercase, {@code false} to 
uppercase.
-     * @param charset the charset.
+     * @param lowerCase if {@code true} then use a lower-case Base16 alphabet.
      * @param decodingPolicy Decoding policy.
      */
-    protected Base16(final boolean toLowerCase, final Charset charset, final 
CodecPolicy decodingPolicy) {
+    public Base16(final boolean lowerCase, final CodecPolicy decodingPolicy) {
         super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, 0, 0,
                 PAD_DEFAULT, decodingPolicy);
-        this.toLowerCase = toLowerCase;
-        this.charset = charset;
-    }
-
-    @Override
-    void encode(final byte[] data, final int offset, final int length, final 
Context context) {
-        if (context.eof) {
-            return;
-        }
-        if (length < 0) {
-            context.eof = true;
-            return;
+        if (lowerCase) {
+            this.encodeTable = LOWER_CASE_ENCODE_TABLE;
+            this.decodeTable = LOWER_CASE_DECODE_TABLE;
+        } else {
+            this.encodeTable = UPPER_CASE_ENCODE_TABLE;
+            this.decodeTable = UPPER_CASE_DECODE_TABLE;
         }
-
-        final char[] chars = Hex.encodeHex(data, offset, length, toLowerCase);
-        final byte[] encoded = new String(chars).getBytes(charset);
-
-        final byte[] buffer = ensureBufferSize(encoded.length, context);
-        System.arraycopy(encoded, 0, buffer, context.pos, encoded.length);
-
-        context.pos += encoded.length;
     }
 
     @Override
-    void decode(final byte[] data, final int offset, final int length, final 
Context context) {
+    void decode(final byte[] data, int offset, final int length, final Context 
context) {
         if (context.eof || length < 0) {
             context.eof = true;
             if (context.ibitWorkArea > 0) {
@@ -119,178 +155,84 @@ public class Base16 extends BaseNCodec {
             return;
         }
 
-        // NOTE: Each pair of bytes is really a pair of hex-chars, therefore 
each pair represents one byte
-
         // we must have an even number of chars to decode
-        final char[] encodedChars = new char[availableChars % 2 == 0 ? 
availableChars : availableChars - 1];
+        final int charsToProcess = availableChars % BYTES_PER_ENCODED_BLOCK == 
0 ? availableChars : availableChars - 1;
+
+        final byte[] buffer = ensureBufferSize(charsToProcess / 
BYTES_PER_ENCODED_BLOCK, context);
 
-        // copy all (or part of) data into encodedChars
+        int result;
         int i = 0;
         if (dataLen < availableChars) {
             // we have 1/2 byte from previous invocation to decode
-            encodedChars[i++] = (char)context.ibitWorkArea;
-            context.ibitWorkArea = -1; // reset for next iteration!
-        }
-        final int copyLen = encodedChars.length - i;
-        for (int j = offset; j < copyLen + offset; j++) {
-            encodedChars[i++] = (char) data[j];
-        }
+            result = decodeTable[context.ibitWorkArea] << 
BITS_PER_ENCODED_BYTE;
+            result |= decodeTable[data[offset++]];
+            i = 2;
 
-        // decode encodedChars into buffer
-        final byte[] buffer = ensureBufferSize(encodedChars.length / 2, 
context);
-        try {
-            final int written = Hex.decodeHex(encodedChars, buffer, 
context.pos);
-            context.pos += written;
-        } catch (final DecoderException e) {
-            throw new RuntimeException(e);  // this method ensures that this 
cannot happen at runtime!
+            buffer[context.pos++] = (byte)result;
+
+            // reset for next invocation!
+            context.ibitWorkArea = -1;
         }
 
-        // we have one char of a hex-pair left over
-        if (copyLen < dataLen) {
-            context.ibitWorkArea = data[offset + dataLen - 1];   // store 1/2 
byte for next invocation of decode
+        while (i < charsToProcess) {
+            result = decodeTable[data[offset++]] << BITS_PER_ENCODED_BYTE;
+            result |= decodeTable[data[offset++]];
+            i += 2;
+            buffer[context.pos++] = (byte)result;
         }
-    }
 
-    /**
-     * Validates whether decoding allows an entire final trailing character 
that cannot be
-     * used for a complete byte.
-     *
-     * @throws IllegalArgumentException if strict decoding is enabled
-     */
-    private void validateTrailingCharacter() {
-        if (isStrictDecoding()) {
-            throw new IllegalArgumentException("Strict decoding: Last encoded 
character is a valid base 16 alphabet" +
-                    "character but not a possible encoding. " +
-                    "Decoding requires at least two characters to create one 
byte.");
+        // we have one char of a hex-pair left over
+        if (i < dataLen) {
+            context.ibitWorkArea = data[i];   // store 1/2 byte for next 
invocation of decode
         }
     }
 
     @Override
-    protected boolean isInAlphabet(final byte value) {
-        if (value >= '0' && value <= '9') {
-            return true;
+    void encode(final byte[] data, final int offset, final int length, final 
Context context) {
+        if (context.eof) {
+            return;
         }
 
-        if (toLowerCase) {
-            return value >= 'a' && value <= 'f';
-        } else {
-            return value >= 'A' && value <= 'F';
+        if (length < 0) {
+            context.eof = true;
+            return;
         }
-    }
 
-    /**
-     * Returns whether or not the {@code c} is in the base 16 alphabet.
-     *
-     * @param c The value to test
-     * @return {@code true} if the value is defined in the the base 16 
alphabet, {@code false} otherwise.
-     */
-    public static boolean isBase16(final char c) {
-        return
-                (c >= '0' && c <= '9')
-                || (c >= 'A' && c <= 'F')
-                || (c >= 'a' && c <= 'f');
-    }
-
-    /**
-     * Tests a given String to see if it contains only valid characters within 
the Base16 alphabet.
-     *
-     * @param base16 String to test
-     * @return {@code true} if all characters in the String are valid 
characters in the Base16 alphabet or if
-     *      the String is empty; {@code false}, otherwise
-     */
-    public static boolean isBase16(final String base16) {
-        return isBase16(base16.toCharArray());
-    }
+        final byte[] buffer = ensureBufferSize(length * 
BYTES_PER_ENCODED_BLOCK, context);
 
-    /**
-     * Tests a given char array to see if it contains only valid characters 
within the Base16 alphabet.
-     *
-     * @param arrayChars char array to test
-     * @return {@code true} if all chars are valid characters in the Base16 
alphabet or if the char array is empty;
-     *         {@code false}, otherwise
-     */
-    public static boolean isBase16(final char[] arrayChars) {
-        for (int i = 0; i < arrayChars.length; i++) {
-            if (!isBase16(arrayChars[i])) {
-                return false;
-            }
+        final int end = offset + length;
+        for (int i = offset; i < end; i++) {
+            final int value = data[i];
+            final int high = (value >> BITS_PER_ENCODED_BYTE) & MASK_4BITS;
+            final int low = value & MASK_4BITS;
+            buffer[context.pos++] = encodeTable[high];
+            buffer[context.pos++] = encodeTable[low];
         }
-        return true;
     }
 
     /**
-     * Tests a given char array to see if it contains only valid characters 
within the Base16 alphabet.
+     * Returns whether or not the {@code octet} is in the Base16 alphabet.
      *
-     * @param arrayChars byte array to test
-     * @return {@code true} if all chars are valid characters in the Base16 
alphabet or if the byte array is empty;
-     *         {@code false}, otherwise
-     */
-    public static boolean isBase16(final byte[] arrayChars) {
-        for (int i = 0; i < arrayChars.length; i++) {
-            if (!isBase16((char) arrayChars[i])) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * Encodes binary data using the base16 algorithm.
+     * @param octet The value to test.
      *
-     * @param binaryData Array containing binary data to encode.
-     * @return Base16-encoded data.
+     * @return {@code true} if the value is defined in the the Base16 alphabet 
{@code false} otherwise.
      */
-    public static byte[] encodeBase16(final byte[] binaryData) {
-        return encodeBase16(binaryData, true, Hex.DEFAULT_CHARSET, 
Integer.MAX_VALUE);
+    @Override
+    public boolean isInAlphabet(final byte octet) {
+        return octet >= 0 && octet < decodeTable.length && decodeTable[octet] 
!= -1;
     }
 
     /**
-     * Encodes binary data using the base16 algorithm.
+     * Validates whether decoding allows an entire final trailing character 
that cannot be
+     * used for a complete byte.
      *
-     * @param binaryData Array containing binary data to encode.
-     * @param toLowerCase {@code true} converts to lowercase, {@code false} to 
uppercase.
-     * @param charset the charset.
-     * @param maxResultSize The maximum result size to accept.
-     * @return Base16-encoded data.
-     * @throws IllegalArgumentException Thrown when the input array needs an 
output array bigger than maxResultSize
+     * @throws IllegalArgumentException if strict decoding is enabled
      */
-    public static byte[] encodeBase16(final byte[] binaryData,  final boolean 
toLowerCase, final Charset charset,
-            final int maxResultSize) {
-        if (binaryData == null || binaryData.length == 0) {
-            return binaryData;
-        }
-
-        // Create this so can use the super-class method
-        // Also ensures that the same roundings are performed by the ctor and 
the code
-        final Base16 b16 = new Base16(toLowerCase, charset);
-        final long len = b16.getEncodedLength(binaryData);
-        if (len > maxResultSize) {
-            throw new IllegalArgumentException("Input array too big, the 
output array would be bigger (" +
-                    len +
-                    ") than the specified maximum size of " +
-                    maxResultSize);
+    private void validateTrailingCharacter() {
+        if (isStrictDecoding()) {
+            throw new IllegalArgumentException("Strict decoding: Last encoded 
character is a valid base 16 alphabet" +
+                    "character but not a possible encoding. " +
+                    "Decoding requires at least two characters to create one 
byte.");
         }
-
-        return b16.encode(binaryData);
-    }
-
-    /**
-     * Decodes a Base16 String into octets.
-     *
-     * @param base16String String containing Base16 data
-     * @return Array containing decoded data.
-     */
-    public static byte[] decodeBase16(final String base16String) {
-        return new Base16().decode(base16String);
-    }
-
-    /**
-     * Decodes Base16 data into octets.
-     *
-     * @param base16Data Byte array containing Base16 data
-     * @return Array containing decoded data.
-     */
-    public static byte[] decodeBase16(final byte[] base16Data) {
-        return new Base16().decode(base16Data);
     }
 }
diff --git 
a/src/main/java/org/apache/commons/codec/binary/Base16InputStream.java 
b/src/main/java/org/apache/commons/codec/binary/Base16InputStream.java
index 94e8cf4..9bd5066 100644
--- a/src/main/java/org/apache/commons/codec/binary/Base16InputStream.java
+++ b/src/main/java/org/apache/commons/codec/binary/Base16InputStream.java
@@ -17,8 +17,9 @@
 
 package org.apache.commons.codec.binary;
 
+import org.apache.commons.codec.CodecPolicy;
+
 import java.io.InputStream;
-import java.nio.charset.Charset;
 
 /**
  * Provides Base16 encoding and decoding in a streaming fashion (unlimited 
size).
@@ -48,7 +49,20 @@ public class Base16InputStream extends BaseNCodecInputStream 
{
      * @param doEncode true if we should encode all data read from us, false 
if we should decode.
      */
     public Base16InputStream(final InputStream in, final boolean doEncode) {
-        this(in, doEncode, true, Hex.DEFAULT_CHARSET);
+        this(in, doEncode, false);
+    }
+
+    /**
+     * Creates a Base16InputStream such that all data read is either 
Base16-encoded or Base16-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 lowerCase if {@code true} then use a lower-case Base16 alphabet.
+     */
+    public Base16InputStream(final InputStream in, final boolean doEncode,
+            final boolean lowerCase) {
+        this(in, doEncode, lowerCase, CodecPolicy.LENIENT);
     }
 
     /**
@@ -57,11 +71,11 @@ public class Base16InputStream extends 
BaseNCodecInputStream {
      *
      * @param in InputStream to wrap.
      * @param doEncode true if we should encode all data read from us, false 
if we should decode.
-     * @param toLowerCase {@code true} converts to lowercase, {@code false} to 
uppercase.
-     * @param charset the charset.
+     * @param lowerCase if {@code true} then use a lower-case Base16 alphabet.
+     * @param decodingPolicy Decoding policy.
      */
     public Base16InputStream(final InputStream in, final boolean doEncode,
-            final boolean toLowerCase, final Charset charset) {
-        super(in, new Base16(toLowerCase, charset), doEncode);
+            final boolean lowerCase, final CodecPolicy decodingPolicy) {
+        super(in, new Base16(lowerCase, decodingPolicy), doEncode);
     }
 }
diff --git 
a/src/main/java/org/apache/commons/codec/binary/Base16OutputStream.java 
b/src/main/java/org/apache/commons/codec/binary/Base16OutputStream.java
index e214320..9a52ab8 100644
--- a/src/main/java/org/apache/commons/codec/binary/Base16OutputStream.java
+++ b/src/main/java/org/apache/commons/codec/binary/Base16OutputStream.java
@@ -17,8 +17,9 @@
 
 package org.apache.commons.codec.binary;
 
+import org.apache.commons.codec.CodecPolicy;
+
 import java.io.OutputStream;
-import java.nio.charset.Charset;
 
 /**
  * Provides Hex encoding and decoding in a streaming fashion (unlimited size).
@@ -48,7 +49,20 @@ public class Base16OutputStream extends 
BaseNCodecOutputStream {
      * @param doEncode true if we should encode all data written to us, false 
if we should decode.
      */
     public Base16OutputStream(final OutputStream out, final boolean doEncode) {
-        this(out, doEncode, true, Hex.DEFAULT_CHARSET);
+        this(out, doEncode, false);
+    }
+
+    /**
+     * Creates a Base16OutputStream such that all data written is either 
Hex-encoded or Hex-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 lowerCase if {@code true} then use a lower-case Base16 alphabet.
+     */
+    public Base16OutputStream(final OutputStream out, final boolean doEncode,
+            final boolean lowerCase) {
+        this(out, doEncode, lowerCase, CodecPolicy.LENIENT);
     }
 
     /**
@@ -57,11 +71,11 @@ public class Base16OutputStream extends 
BaseNCodecOutputStream {
      *
      * @param out OutputStream to wrap.
      * @param doEncode true if we should encode all data written to us, false 
if we should decode.
-     * @param toLowerCase {@code true} converts to lowercase, {@code false} to 
uppercase.
-     * @param charset the charset.
+     * @param lowerCase if {@code true} then use a lower-case Base16 alphabet.
+     * @param decodingPolicy Decoding policy.
      */
     public Base16OutputStream(final OutputStream out, final boolean doEncode,
-            final boolean toLowerCase, final Charset charset) {
-        super(out, new Base16(toLowerCase, charset), doEncode);
+            final boolean lowerCase, final CodecPolicy decodingPolicy) {
+        super(out, new Base16(lowerCase, decodingPolicy), doEncode);
     }
 }
diff --git 
a/src/test/java/org/apache/commons/codec/binary/Base16InputStreamTest.java 
b/src/test/java/org/apache/commons/codec/binary/Base16InputStreamTest.java
index 9d4d2a2..c3c8ee0 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base16InputStreamTest.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base16InputStreamTest.java
@@ -36,7 +36,7 @@ public class Base16InputStreamTest {
     /**
      * Decodes to {202, 254, 186, 190, 255, 255}
      */
-    private static final String ENCODED_B16 = "cafebabeffff";
+    private static final String ENCODED_B16 = "CAFEBABEFFFF";
 
     private static final String STRING_FIXTURE = "Hello World";
 
@@ -81,7 +81,7 @@ public class Base16InputStreamTest {
     @Test
     public void testBase16InputStreamByChunk() throws IOException {
         // Hello World test.
-        byte[] encoded = StringUtils.getBytesUtf8("48656c6c6f20576f726c64");
+        byte[] encoded = StringUtils.getBytesUtf8("48656C6C6F20576F726C64");
         byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE);
         testByChunk(encoded, decoded);
 
@@ -91,7 +91,7 @@ public class Base16InputStreamTest {
         testByChunk(encoded, decoded);
 
         // OpenSSL interop test.
-        encoded = 
StringUtils.getBytesUtf8(Base16TestData.ENCODED_UTF8_LOWERCASE);
+        encoded = 
StringUtils.getBytesUtf8(Base16TestData.ENCODED_UTF8_UPPERCASE);
         decoded = Base16TestData.DECODED;
         testByChunk(encoded, decoded);
 
@@ -100,7 +100,7 @@ public class Base16InputStreamTest {
             final byte[][] randomData = Base16TestData.randomData(i);
             encoded = randomData[1];
             decoded = randomData[0];
-            testByChunk(encoded, decoded);
+            testByChunk(encoded, decoded, true);
         }
     }
 
@@ -112,7 +112,7 @@ public class Base16InputStreamTest {
     @Test
     public void testBase16InputStreamByteByByte() throws IOException {
         // Hello World test.
-        byte[] encoded = StringUtils.getBytesUtf8("48656c6c6f20576f726c64");
+        byte[] encoded = StringUtils.getBytesUtf8("48656C6C6F20576F726C64");
         byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE);
         testByteByByte(encoded, decoded);
 
@@ -122,7 +122,7 @@ public class Base16InputStreamTest {
         testByteByByte(encoded, decoded);
 
         // OpenSSL interop test.
-        encoded = 
StringUtils.getBytesUtf8(Base16TestData.ENCODED_UTF8_LOWERCASE);
+        encoded = 
StringUtils.getBytesUtf8(Base16TestData.ENCODED_UTF8_UPPERCASE);
         decoded = Base16TestData.DECODED;
         testByteByByte(encoded, decoded);
 
@@ -131,7 +131,7 @@ public class Base16InputStreamTest {
             final byte[][] randomData = Base16TestData.randomData(i);
             encoded = randomData[1];
             decoded = randomData[0];
-            testByteByByte(encoded, decoded);
+            testByteByByte(encoded, decoded, true);
         }
     }
 
@@ -147,38 +147,52 @@ public class Base16InputStreamTest {
      * @throws IOException Usually signifies a bug in the Base16 commons-codec 
implementation.
      */
     private void testByChunk(final byte[] encoded, final byte[] decoded) 
throws IOException {
+        testByChunk(encoded, decoded, false);
+    }
 
-        // Start with encode.
-        InputStream in;
-        in = new Base16InputStream(new ByteArrayInputStream(decoded), true);
-        byte[] output = Base16TestData.streamToBytes(in);
+    /**
+     * Tests method does three tests on the supplied data: 1. encoded 
---[DECODE]--> decoded 2. decoded ---[ENCODE]--> encoded 3. decoded
+     * ---[WRAP-WRAP-WRAP-etc...] --> decoded
+     * <p/>
+     * By "[WRAP-WRAP-WRAP-etc...]" we mean situation where the 
Base16InputStream wraps itself in encode and decode mode over and over
+     * again.
+     *
+     * @param encoded Base16 encoded data
+     * @param decoded the data from above, but decoded
+     * @param lowerCase if {@code true} then use a lower-case Base16 alphabet
+     * @throws IOException Usually signifies a bug in the Base16 commons-codec 
implementation.
+     */
+    private void testByChunk(final byte[] encoded, final byte[] decoded, final 
boolean lowerCase) throws IOException {
 
-        assertEquals("EOF", -1, in.read());
-        assertEquals("Still EOF", -1, in.read());
-        assertArrayEquals("Streaming Base16 encode", encoded, output);
+        // Start with encode.
+        try (final InputStream in = new Base16InputStream(new 
ByteArrayInputStream(decoded), true, lowerCase)) {
+            final byte[] output = Base16TestData.streamToBytes(in);
 
-        in.close();
+            assertEquals("EOF", -1, in.read());
+            assertEquals("Still EOF", -1, in.read());
+            assertArrayEquals("Streaming Base16 encode", encoded, output);
+        }
 
         // Now let's try decode.
-        in = new Base16InputStream(new ByteArrayInputStream(encoded));
-        output = Base16TestData.streamToBytes(in);
-
-        assertEquals("EOF", -1, in.read());
-        assertEquals("Still EOF", -1, in.read());
-        assertArrayEquals("Streaming Base16 decode", decoded, output);
-
-        // I always wanted to do this! (wrap encoder with decoder etc etc).
-        in = new ByteArrayInputStream(decoded);
-        for (int i = 0; i < 10; i++) {
-            in = new Base16InputStream(in, true);
-            in = new Base16InputStream(in, false);
+        try (final InputStream in = new Base16InputStream(new 
ByteArrayInputStream(encoded), false, lowerCase)) {
+            final byte[] output = Base16TestData.streamToBytes(in);
+
+            assertEquals("EOF", -1, in.read());
+            assertEquals("Still EOF", -1, in.read());
+            assertArrayEquals("Streaming Base16 decode", decoded, output);
         }
-        output = Base16TestData.streamToBytes(in);
 
-        assertEquals("EOF", -1, in.read());
-        assertEquals("Still EOF", -1, in.read());
-        assertArrayEquals("Streaming Base16 wrap-wrap-wrap!", decoded, output);
-        in.close();
+        // wrap encoder with decoder
+        try (final InputStream in = new ByteArrayInputStream(decoded);
+                final InputStream inEncode = new Base16InputStream(in, true, 
lowerCase);
+                final InputStream inDecode = new Base16InputStream(inEncode, 
false, lowerCase)) {
+
+            final byte[] output = Base16TestData.streamToBytes(inDecode);
+
+            assertEquals("EOF", -1, inDecode.read());
+            assertEquals("Still EOF", -1, inDecode.read());
+            assertArrayEquals("Streaming Base16 wrap-wrap!", decoded, output);
+        }
     }
 
     /**
@@ -193,48 +207,61 @@ public class Base16InputStreamTest {
      * @throws IOException Usually signifies a bug in the Base16 commons-codec 
implementation.
      */
     private void testByteByByte(final byte[] encoded, final byte[] decoded) 
throws IOException {
+        testByteByByte(encoded, decoded, false);
+    }
+
+    /**
+     * Tests method does three tests on the supplied data: 1. encoded 
---[DECODE]--> decoded 2. decoded ---[ENCODE]--> encoded 3. decoded
+     * ---[WRAP-WRAP-WRAP-etc...] --> decoded
+     * <p/>
+     * By "[WRAP-WRAP-WRAP-etc...]" we mean situation where the 
Base16InputStream wraps itself in encode and decode mode over and over
+     * again.
+     *
+     * @param encoded Base16 encoded data
+     * @param decoded the data from above, but decoded
+     * @param lowerCase if {@code true} then use a lower-case Base16 alphabet
+     * @throws IOException Usually signifies a bug in the Base16 commons-codec 
implementation.
+     */
+    private void testByteByByte(final byte[] encoded, final byte[] decoded, 
final boolean lowerCase) throws IOException {
 
         // Start with encode.
-        InputStream in;
-        in = new Base16InputStream(new ByteArrayInputStream(decoded), true);
-        byte[] output = new byte[encoded.length];
-        for (int i = 0; i < output.length; i++) {
-            output[i] = (byte) in.read();
-        }
+        try (final InputStream in = new Base16InputStream(new 
ByteArrayInputStream(decoded), true, lowerCase)) {
+            final byte[] output = new byte[encoded.length];
+            for (int i = 0; i < output.length; i++) {
+                output[i] = (byte) in.read();
+            }
 
-        assertEquals("EOF", -1, in.read());
-        assertEquals("Still EOF", -1, in.read());
-        assertArrayEquals("Streaming Base16 encode", encoded, output);
+            assertEquals("EOF", -1, in.read());
+            assertEquals("Still EOF", -1, in.read());
+            assertArrayEquals("Streaming Base16 encode", encoded, output);
+        }
 
-        in.close();
         // Now let's try decode.
-        in = new Base16InputStream(new ByteArrayInputStream(encoded));
-        output = new byte[decoded.length];
-        for (int i = 0; i < output.length; i++) {
-            output[i] = (byte) in.read();
+        try (final InputStream in = new Base16InputStream(new 
ByteArrayInputStream(encoded), false, lowerCase)) {
+            final byte[] output = new byte[decoded.length];
+            for (int i = 0; i < output.length; i++) {
+                output[i] = (byte) in.read();
+            }
+
+            assertEquals("EOF", -1, in.read());
+            assertEquals("Still EOF", -1, in.read());
+            assertArrayEquals("Streaming Base16 decode", decoded, output);
         }
 
-        assertEquals("EOF", -1, in.read());
-        assertEquals("Still EOF", -1, in.read());
-        assertArrayEquals("Streaming Base16 decode", decoded, output);
+        // wrap encoder with decoder
+        try (final InputStream in = new ByteArrayInputStream(decoded);
+                final InputStream inEncode = new Base16InputStream(in, true, 
lowerCase);
+                final InputStream inDecode = new Base16InputStream(inEncode, 
false, lowerCase)) {
 
-        in.close();
+            final byte[] output = new byte[decoded.length];
+            for (int i = 0; i < output.length; i++) {
+                output[i] = (byte) inDecode.read();
+            }
 
-        // I always wanted to do this! (wrap encoder with decoder etc etc).
-        in = new ByteArrayInputStream(decoded);
-        for (int i = 0; i < 10; i++) {
-            in = new Base16InputStream(in, true);
-            in = new Base16InputStream(in, false);
+            assertEquals("EOF", -1, inDecode.read());
+            assertEquals("Still EOF", -1, inDecode.read());
+            assertArrayEquals("Streaming Base16 wrap-wrap!", decoded, output);
         }
-        output = new byte[decoded.length];
-        for (int i = 0; i < output.length; i++) {
-            output[i] = (byte) in.read();
-        }
-
-        assertEquals("EOF", -1, in.read());
-        assertEquals("Still EOF", -1, in.read());
-        assertArrayEquals("Streaming Base16 wrap-wrap-wrap!", decoded, output);
-        in.close();
     }
 
     /**
diff --git 
a/src/test/java/org/apache/commons/codec/binary/Base16OutputStreamTest.java 
b/src/test/java/org/apache/commons/codec/binary/Base16OutputStreamTest.java
index 6f91f51..6bb5d34 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base16OutputStreamTest.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base16OutputStreamTest.java
@@ -54,7 +54,7 @@ public class Base16OutputStreamTest {
     @Test
     public void testBase16OutputStreamByChunk() throws Exception {
         // Hello World test.
-        byte[] encoded = StringUtils.getBytesUtf8("48656c6c6f20576f726c64");
+        byte[] encoded = StringUtils.getBytesUtf8("48656C6C6F20576F726C64");
         byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE);
         testByChunk(encoded, decoded);
 
@@ -68,7 +68,7 @@ public class Base16OutputStreamTest {
             final byte[][] randomData = Base16TestData.randomData(i);
             encoded = randomData[1];
             decoded = randomData[0];
-            testByChunk(encoded, decoded);
+            testByChunk(encoded, decoded, true);
         }
     }
 
@@ -80,7 +80,7 @@ public class Base16OutputStreamTest {
     @Test
     public void testBase16OutputStreamByteByByte() throws IOException {
         // Hello World test.
-        byte[] encoded = StringUtils.getBytesUtf8("48656c6c6f20576f726c64");
+        byte[] encoded = StringUtils.getBytesUtf8("48656C6C6F20576F726C64");
         byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE);
         testByteByByte(encoded, decoded);
 
@@ -94,7 +94,7 @@ public class Base16OutputStreamTest {
             final byte[][] randomData = Base16TestData.randomData(i);
             encoded = randomData[1];
             decoded = randomData[0];
-            testByteByByte(encoded, decoded);
+            testByteByByte(encoded, decoded, true);
         }
     }
 
@@ -105,43 +105,54 @@ public class Base16OutputStreamTest {
      * By "[WRAP-WRAP-WRAP-etc...]" we mean situation where the 
Base16OutputStream wraps itself in encode and decode
      * mode over and over again.
      *
-     * @param encoded
-     *            base16 encoded data
-     * @param decoded
-     *            the data from above, but decoded
-     * @throws IOException
-     *             Usually signifies a bug in the Base16 commons-codec 
implementation.
+     * @param encoded base16 encoded data
+     * @param decoded the data from above, but decoded
+     * @throws IOException Usually signifies a bug in the Base16 commons-codec 
implementation.
      */
     private void testByChunk(final byte[] encoded, final byte[] decoded) 
throws IOException {
+        testByChunk(encoded, decoded, false);
+    }
+
+    /**
+     * Test method does three tests on the supplied data: 1. encoded 
---[DECODE]--> decoded 2. decoded ---[ENCODE]-->
+     * encoded 3. decoded ---[WRAP-WRAP-WRAP-etc...] --> decoded
+     * <p/>
+     * By "[WRAP-WRAP-WRAP-etc...]" we mean situation where the 
Base16OutputStream wraps itself in encode and decode
+     * mode over and over again.
+     *
+     * @param encoded base16 encoded data
+     * @param decoded the data from above, but decoded
+     * @param lowerCase if {@code true} then use a lower-case Base16 alphabet
+     * @throws IOException Usually signifies a bug in the Base16 commons-codec 
implementation.
+     */
+    private void testByChunk(final byte[] encoded, final byte[] decoded, final 
boolean lowerCase) throws IOException {
 
         // Start with encode.
-        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
-        OutputStream out = new Base16OutputStream(byteOut, true);
-        out.write(decoded);
-        out.close();
-        byte[] output = byteOut.toByteArray();
-        assertArrayEquals("Streaming chunked base16 encode", encoded, output);
+        try (final ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+                final OutputStream out = new Base16OutputStream(byteOut, true, 
lowerCase)) {
+            out.write(decoded);
+            final byte[] output = byteOut.toByteArray();
+            assertArrayEquals("Streaming chunked base16 encode", encoded, 
output);
+        }
 
         // Now let's try decode.
-        byteOut = new ByteArrayOutputStream();
-        out = new Base16OutputStream(byteOut, false);
-        out.write(encoded);
-        out.close();
-        output = byteOut.toByteArray();
-        assertArrayEquals("Streaming chunked base16 decode", decoded, output);
-
-        // I always wanted to do this! (wrap encoder with decoder etc etc).
-        byteOut = new ByteArrayOutputStream();
-        out = byteOut;
-        for (int i = 0; i < 10; i++) {
-            out = new Base16OutputStream(out, false);
-            out = new Base16OutputStream(out, true);
+        try (final ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+                final OutputStream out = new Base16OutputStream(byteOut, 
false, lowerCase)) {
+            out.write(encoded);
+            final byte[] output = byteOut.toByteArray();
+            assertArrayEquals("Streaming chunked base16 decode", decoded, 
output);
         }
-        out.write(decoded);
-        out.close();
-        output = byteOut.toByteArray();
 
-        assertArrayEquals("Streaming chunked base16 wrap-wrap-wrap!", decoded, 
output);
+        // wrap encoder with decoder
+        try (final ByteArrayOutputStream byteOut = new 
ByteArrayOutputStream()) {
+            final OutputStream decoderOut = new Base16OutputStream(byteOut, 
false, lowerCase);
+            final OutputStream encoderOut = new Base16OutputStream(decoderOut, 
true, lowerCase);
+
+            encoderOut.write(decoded);
+            final byte[] output = byteOut.toByteArray();
+
+            assertArrayEquals("Streaming chunked base16 wrap-wrap!", decoded, 
output);
+        }
     }
 
     /**
@@ -151,60 +162,68 @@ public class Base16OutputStreamTest {
      * By "[WRAP-WRAP-WRAP-etc...]" we mean situation where the 
Base16OutputStream wraps itself in encode and decode
      * mode over and over again.
      *
-     * @param encoded
-     *            base16 encoded data
-     * @param decoded
-     *            the data from above, but decoded
-     * @throws IOException
-     *             Usually signifies a bug in the Base16 commons-codec 
implementation.
+     * @param encoded base16 encoded data
+     * @param decoded the data from above, but decoded
+     * @throws IOException Usually signifies a bug in the Base16 commons-codec 
implementation.
      */
     private void testByteByByte(final byte[] encoded, final byte[] decoded) 
throws IOException {
+        testByteByByte(encoded, decoded, false);
+    }
+
+    /**
+     * Test method does three tests on the supplied data: 1. encoded 
---[DECODE]--> decoded 2. decoded ---[ENCODE]-->
+     * encoded 3. decoded ---[WRAP-WRAP-WRAP-etc...] --> decoded
+     * <p/>
+     * By "[WRAP-WRAP-WRAP-etc...]" we mean situation where the 
Base16OutputStream wraps itself in encode and decode
+     * mode over and over again.
+     *
+     * @param encoded base16 encoded data
+     * @param decoded the data from above, but decoded
+     * @throws IOException Usually signifies a bug in the Base16 commons-codec 
implementation.
+     */
+    private void testByteByByte(final byte[] encoded, final byte[] decoded, 
final boolean lowerCase) throws IOException {
 
         // Start with encode.
-        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
-        OutputStream out = new Base16OutputStream(byteOut, true);
-        for (final byte element : decoded) {
-            out.write(element);
+        try (final ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+                final OutputStream out = new Base16OutputStream(byteOut, true, 
lowerCase)) {
+            for (final byte element : decoded) {
+                out.write(element);
+            }
+            final byte[] output = byteOut.toByteArray();
+            assertArrayEquals("Streaming byte-by-byte base16 encode", encoded, 
output);
         }
-        out.close();
-        byte[] output = byteOut.toByteArray();
-        assertArrayEquals("Streaming byte-by-byte base16 encode", encoded, 
output);
 
         // Now let's try decode.
-        byteOut = new ByteArrayOutputStream();
-        out = new Base16OutputStream(byteOut, false);
-        for (final byte element : encoded) {
-            out.write(element);
+        try (final ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+                final OutputStream out = new Base16OutputStream(byteOut, 
false, lowerCase)) {
+            for (final byte element : encoded) {
+                out.write(element);
+            }
+            final byte[] output = byteOut.toByteArray();
+            assertArrayEquals("Streaming byte-by-byte base16 decode", decoded, 
output);
         }
-        out.close();
-        output = byteOut.toByteArray();
-        assertArrayEquals("Streaming byte-by-byte base16 decode", decoded, 
output);
 
         // Now let's try decode with tonnes of flushes.
-        byteOut = new ByteArrayOutputStream();
-        out = new Base16OutputStream(byteOut, false);
-        for (final byte element : encoded) {
-            out.write(element);
-            out.flush();
-        }
-        out.close();
-        output = byteOut.toByteArray();
-        assertArrayEquals("Streaming byte-by-byte flush() base16 decode", 
decoded, output);
-
-        // I always wanted to do this! (wrap encoder with decoder etc etc).
-        byteOut = new ByteArrayOutputStream();
-        out = byteOut;
-        for (int i = 0; i < 10; i++) {
-            out = new Base16OutputStream(out, false);
-            out = new Base16OutputStream(out, true);
-        }
-        for (final byte element : decoded) {
-            out.write(element);
+        try (final ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+                final OutputStream out = new Base16OutputStream(byteOut, 
false, lowerCase)) {
+            for (final byte element : encoded) {
+                out.write(element);
+                out.flush();
+            }
+            final byte[] output = byteOut.toByteArray();
+            assertArrayEquals("Streaming byte-by-byte flush() base16 decode", 
decoded, output);
         }
-        out.close();
-        output = byteOut.toByteArray();
 
-        assertArrayEquals("Streaming byte-by-byte base16 wrap-wrap-wrap!", 
decoded, output);
+        // wrap encoder with decoder
+        try (final ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+                final OutputStream decoderOut = new 
Base16OutputStream(byteOut, false, lowerCase);
+                final OutputStream encoderOut = new 
Base16OutputStream(decoderOut, true, lowerCase)) {
+            for (final byte element : decoded) {
+                encoderOut.write(element);
+            }
+            final byte[] output = byteOut.toByteArray();
+            assertArrayEquals("Streaming byte-by-byte base16 wrap-wrap!", 
decoded, output);
+        }
     }
 
     /**
diff --git a/src/test/java/org/apache/commons/codec/binary/Base16Test.java 
b/src/test/java/org/apache/commons/codec/binary/Base16Test.java
index eb273fa..989520a 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base16Test.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base16Test.java
@@ -29,11 +29,9 @@ import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
 import java.util.Random;
 
-import static org.apache.commons.codec.CharEncoding.UTF_8;
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
@@ -56,43 +54,18 @@ public class Base16Test {
     }
 
     /**
-     * Test the isStringBase16 method.
-     */
-    @Test
-    public void testIsStringBase16() {
-        final String nullString = null;
-        final String emptyString = "";
-        final String validString = "cafebabec0a1f2e3b4a5b6e7c8";
-        final String invalidString = validString + (char) 0; // append null
-                                                                // character
-
-        try {
-            Base16.isBase16(nullString);
-            fail("Base16.isStringBase16() should not be null-safe.");
-        } catch (final NullPointerException npe) {
-            assertNotNull("Base16.isStringBase16() should not be null-safe.", 
npe);
-        }
-
-        assertTrue("Base16.isStringBase16(empty-string) is true", 
Base16.isBase16(emptyString));
-        assertTrue("Base16.isStringBase16(valid-string) is true", 
Base16.isBase16(validString));
-        assertFalse("Base16.isStringBase16(invalid-string) is false", 
Base16.isBase16(invalidString));
-    }
-
-    /**
      * Test the Base16 implementation
      */
     @Test
     public void testBase16() {
         final String content = "Hello World";
-        String encodedContent;
-        byte[] encodedBytes = 
Base16.encodeBase16(StringUtils.getBytesUtf8(content));
-        encodedContent = StringUtils.newStringUtf8(encodedBytes);
-        assertEquals("encoding hello world", "48656c6c6f20576f726c64", 
encodedContent);
+        final byte[] encodedBytes = new 
Base16().encode(StringUtils.getBytesUtf8(content));
+        final String encodedContent = StringUtils.newStringUtf8(encodedBytes);
+        assertEquals("encoding hello world", "48656C6C6F20576F726C64", 
encodedContent);
 
-        Base16 b16 = new Base16();
-        encodedBytes = b16.encode(StringUtils.getBytesUtf8(content));
-        encodedContent = StringUtils.newStringUtf8(encodedBytes);
-        assertEquals("encoding hello world", "48656c6c6f20576f726c64", 
encodedContent);
+        final byte[] decodedBytes = new Base16().decode(encodedBytes);
+        final String decodedContent = StringUtils.newStringUtf8(decodedBytes);
+        assertEquals("decoding hello world", content, decodedContent);
     }
 
     @Test
@@ -118,7 +91,7 @@ public class Base16Test {
         buffer = ArrayUtils.addAll(new byte[startPasSize], buffer);
         final byte[] encodedBytes = new Base16().encode(buffer, startPasSize, 
bytesUtf8.length);
         encodedContent = StringUtils.newStringUtf8(encodedBytes);
-        assertEquals("encoding hello world", "48656c6c6f20576f726c64", 
encodedContent);
+        assertEquals("encoding hello world", "48656C6C6F20576F726C64", 
encodedContent);
     }
 
     /**
@@ -128,33 +101,35 @@ public class Base16Test {
     @Test(expected=RuntimeException.class)
     public void testCodec68() {
         final byte[] x = new byte[] { 'n', 'H', '=', '=', (byte) 0x9c };
-        Base16.decodeBase16(x);
+        final Base16 b16 = new Base16();
+        b16.decode(x);
     }
 
     @Test
     public void testConstructors() {
         new Base16();
-        new Base16();
-        new Base16(CHARSET_UTF8);
-        new Base16(false, CHARSET_UTF8);
+        new Base16(false);
+        new Base16(true);
+        new Base16(false, CodecPolicy.LENIENT);
+        new Base16(false, CodecPolicy.STRICT);
     }
 
     @Test
-    public void testConstructor_Charset() {
-        final Base16 Base16 = new Base16(CHARSET_UTF8);
+    public void testConstructor_LowerCase() {
+        final Base16 Base16 = new Base16(true);
         final byte[] encoded = Base16.encode(Base16TestData.DECODED);
         final String expectedResult = Base16TestData.ENCODED_UTF8_LOWERCASE;
         final String result = StringUtils.newStringUtf8(encoded);
-        assertEquals("new Base16(UTF_8)", expectedResult, result);
+        assertEquals("new Base16(true)", expectedResult, result);
     }
 
     @Test
-    public void testConstructor_Boolean_Charset() {
-        final Base16 Base16 = new Base16(false, CHARSET_UTF8);
+    public void testConstructor_LowerCase_DecodingPolicy() {
+        final Base16 Base16 = new Base16(false, CodecPolicy.STRICT);
         final byte[] encoded = Base16.encode(Base16TestData.DECODED);
         final String expectedResult = Base16TestData.ENCODED_UTF8_UPPERCASE;
         final String result = StringUtils.newStringUtf8(encoded);
-        assertEquals("new Base16(false, UTF_8)", result, expectedResult);
+        assertEquals("new Base16(false, CodecPolicy.STRICT)", result, 
expectedResult);
     }
 
     /**
@@ -163,14 +138,14 @@ public class Base16Test {
     @Test
     public void testEmptyBase16() {
         byte[] empty = new byte[0];
-        byte[] result = Base16.encodeBase16(empty);
+        byte[] result = new Base16().encode(empty);
         assertEquals("empty Base16 encode", 0, result.length);
-        assertEquals("empty Base16 encode", null, Base16.encodeBase16(null));
+        assertEquals("empty Base16 encode", null, new Base16().encode(null));
 
         empty = new byte[0];
-        result = Base16.decodeBase16(empty);
+        result = new Base16().decode(empty);
         assertEquals("empty Base16 decode", 0, result.length);
-        assertEquals("empty Base16 encode", null, Base16.decodeBase16((byte[]) 
null));
+        assertEquals("empty Base16 encode", null, new Base16().decode((byte[]) 
null));
     }
 
     // encode/decode a large random array
@@ -180,9 +155,8 @@ public class Base16Test {
             final int len = this.getRandom().nextInt(10000) + 1;
             final byte[] data = new byte[len];
             this.getRandom().nextBytes(data);
-            final byte[] enc = Base16.encodeBase16(data);
-            assertTrue(Base16.isBase16(enc));
-            final byte[] data2 = Base16.decodeBase16(enc);
+            final byte[] enc = new Base16().encode(data);
+            final byte[] data2 = new Base16().decode(enc);
             assertArrayEquals(data, data2);
         }
     }
@@ -193,82 +167,46 @@ public class Base16Test {
         for (int i = 0; i < 12; i++) {
             final byte[] data = new byte[i];
             this.getRandom().nextBytes(data);
-            final byte[] enc = Base16.encodeBase16(data);
-            assertTrue("\"" + new String(enc) + "\" is Base16 data.", 
Base16.isBase16(enc));
-            final byte[] data2 = Base16.decodeBase16(enc);
+            final byte[] enc = new Base16().encode(data);
+            final byte[] data2 = new Base16().decode(enc);
             assertArrayEquals(toString(data) + " equals " + toString(data2), 
data, data2);
         }
     }
 
     @Test
-    public void testEncodeOverMaxSize() {
-        testEncodeOverMaxSize(-1);
-        testEncodeOverMaxSize(0);
-        testEncodeOverMaxSize(1);
-        testEncodeOverMaxSize(2);
-    }
-
-    private void testEncodeOverMaxSize(final int maxSize) {
-        try {
-            Base16.encodeBase16(Base16TestData.DECODED, true, CHARSET_UTF8, 
maxSize);
-            fail("Expected " + IllegalArgumentException.class.getName());
-        } catch (final IllegalArgumentException e) {
-            // Expected
-        }
-    }
-
-    @Test
-    public void testIsArrayByteBase16() {
-        assertFalse(Base16.isBase16(new char[] { (char)Byte.MIN_VALUE }));
-        assertFalse(Base16.isBase16(new char[] { (char)-125 }));
-        assertFalse(Base16.isBase16(new char[] { (char)-10 }));
-        assertFalse(Base16.isBase16(new char[] { 0 }));
-        assertFalse(Base16.isBase16(new char[] { 64, Byte.MAX_VALUE }));
-        assertFalse(Base16.isBase16(new char[] { Byte.MAX_VALUE }));
-        assertTrue(Base16.isBase16(new char[] { 'A' }));
-        assertFalse(Base16.isBase16(new char[] { 'A', (char)Byte.MIN_VALUE }));
-        assertTrue(Base16.isBase16(new char[] { 'A', 'F', 'a' }));
-        assertFalse(Base16.isBase16(new char[] { '/', '=', '+' }));
-        assertFalse(Base16.isBase16(new char[] { '$' }));
-    }
-
-    @Test
     public void testKnownDecodings() {
-        assertEquals("The quick brown fox jumped over the lazy dogs.", new 
String(Base16.decodeBase16(
+        assertEquals("The quick brown fox jumped over the lazy dogs.", new 
String(new Base16(true).decode(
                 
"54686520717569636b2062726f776e20666f78206a756d706564206f76657220746865206c617a7920646f67732e".getBytes(CHARSET_UTF8))));
-        assertEquals("It was the best of times, it was the worst of times.", 
new String(Base16.decodeBase16(
+        assertEquals("It was the best of times, it was the worst of times.", 
new String(new Base16(true).decode(
                 
"497420776173207468652062657374206f662074696d65732c206974207761732074686520776f727374206f662074696d65732e".getBytes(CHARSET_UTF8))));
         assertEquals("http://jakarta.apache.org/commmons";, new String(
-                
Base16.decodeBase16("687474703a2f2f6a616b617274612e6170616368652e6f72672f636f6d6d6d6f6e73".getBytes(CHARSET_UTF8))));
-        assertEquals("AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz", 
new String(Base16.decodeBase16(
+                new 
Base16(true).decode("687474703a2f2f6a616b617274612e6170616368652e6f72672f636f6d6d6d6f6e73".getBytes(CHARSET_UTF8))));
+        assertEquals("AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz", 
new String(new Base16(true).decode(
                 
"4161426243634464456546664767486849694a6a4b6b4c6c4d6d4e6e4f6f50705171527253735474557556765777587859795a7a".getBytes(CHARSET_UTF8))));
         assertEquals("{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }",
-                new 
String(Base16.decodeBase16("7b20302c20312c20322c20332c20342c20352c20362c20372c20382c2039207d".getBytes(CHARSET_UTF8))));
-        assertEquals("xyzzy!", new 
String(Base16.decodeBase16("78797a7a7921".getBytes(CHARSET_UTF8))));
+                new String(new 
Base16(true).decode("7b20302c20312c20322c20332c20342c20352c20362c20372c20382c2039207d".getBytes(CHARSET_UTF8))));
+        assertEquals("xyzzy!", new String(new 
Base16(true).decode("78797a7a7921".getBytes(CHARSET_UTF8))));
     }
 
     @Test
     public void testKnownEncodings() {
         
assertEquals("54686520717569636b2062726f776e20666f78206a756d706564206f76657220746865206c617a7920646f67732e",
 new String(
-                Base16.encodeBase16("The quick brown fox jumped over the lazy 
dogs.".getBytes(CHARSET_UTF8))));
+                new Base16(true).encode("The quick brown fox jumped over the 
lazy dogs.".getBytes(CHARSET_UTF8))));
         
assertEquals("497420776173207468652062657374206f662074696d65732c206974207761732074686520776f727374206f662074696d65732e",
 new String(
-                Base16.encodeBase16("It was the best of times, it was the 
worst of times.".getBytes(CHARSET_UTF8))));
+                new Base16(true).encode("It was the best of times, it was the 
worst of times.".getBytes(CHARSET_UTF8))));
         
assertEquals("687474703a2f2f6a616b617274612e6170616368652e6f72672f636f6d6d6d6f6e73",
-                new 
String(Base16.encodeBase16("http://jakarta.apache.org/commmons".getBytes(CHARSET_UTF8))));
+                new String(new 
Base16(true).encode("http://jakarta.apache.org/commmons".getBytes(CHARSET_UTF8))));
         
assertEquals("4161426243634464456546664767486849694a6a4b6b4c6c4d6d4e6e4f6f50705171527253735474557556765777587859795a7a",
 new String(
-                
Base16.encodeBase16("AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz".getBytes(CHARSET_UTF8))));
+                new 
Base16(true).encode("AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz".getBytes(CHARSET_UTF8))));
         
assertEquals("7b20302c20312c20322c20332c20342c20352c20362c20372c20382c2039207d",
-                new String(Base16.encodeBase16("{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 
}".getBytes(CHARSET_UTF8))));
-        assertEquals("78797a7a7921", new 
String(Base16.encodeBase16("xyzzy!".getBytes(CHARSET_UTF8))));
+                new String(new Base16(true).encode("{ 0, 1, 2, 3, 4, 5, 6, 7, 
8, 9 }".getBytes(CHARSET_UTF8))));
+        assertEquals("78797a7a7921", new String(new 
Base16(true).encode("xyzzy!".getBytes(CHARSET_UTF8))));
     }
 
     @Test
     public void testNonBase16Test() {
         final byte[] bArray = { '%' };
 
-        assertFalse("Invalid Base16 array was incorrectly validated as " + "an 
array of Base16 encoded data",
-                Base16.isBase16(bArray));
-
         try {
             final Base16 b16 = new Base16();
             final byte[] result = b16.decode(bArray);
@@ -296,7 +234,7 @@ public class Base16Test {
     @Test
     public void testObjectDecodeWithValidParameter() throws Exception {
         final String original = "Hello World!";
-        final Object o = Base16.encodeBase16(original.getBytes(CHARSET_UTF8));
+        final Object o = new Base16().encode(original.getBytes(CHARSET_UTF8));
 
         final Base16 b16 = new Base16();
         final Object oDecoded = b16.decode(o);
@@ -322,9 +260,8 @@ public class Base16Test {
         final String original = "Hello World!";
         final Object origObj = original.getBytes(CHARSET_UTF8);
 
-        final Base16 b16 = new Base16();
-        final Object oEncoded = b16.encode(origObj);
-        final byte[] bArray = Base16.decodeBase16((byte[]) oEncoded);
+        final Object oEncoded = new Base16().encode(origObj);
+        final byte[] bArray = new Base16().decode((byte[]) oEncoded);
         final String dest = new String(bArray);
 
         assertEquals("dest string does not equal original", original, dest);
@@ -333,149 +270,166 @@ public class Base16Test {
     @Test
     public void testObjectEncode() {
         final Base16 b16 = new Base16();
-        assertEquals("48656c6c6f20576f726c64", new String(b16.encode("Hello 
World".getBytes(CHARSET_UTF8))));
+        assertEquals("48656C6C6F20576F726C64", new String(b16.encode("Hello 
World".getBytes(CHARSET_UTF8))));
     }
 
     @Test
     public void testPairs() {
-        assertEquals("0000", new String(Base16.encodeBase16(new byte[] { 0, 0 
})));
+        assertEquals("0000", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 0 })));
+        assertEquals("0001", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 1 })));
+        assertEquals("0002", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 2 })));
+        assertEquals("0003", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 3 })));
+        assertEquals("0004", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 4 })));
+        assertEquals("0005", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 5 })));
+        assertEquals("0006", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 6 })));
+        assertEquals("0007", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 7 })));
+        assertEquals("0008", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 8 })));
+        assertEquals("0009", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 9 })));
+        assertEquals("000A", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 10 })));
+        assertEquals("000B", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 11 })));
+        assertEquals("000C", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 12 })));
+        assertEquals("000D", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 13 })));
+        assertEquals("000E", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 14 })));
+        assertEquals("000F", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 15 })));
+        assertEquals("0010", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 16 })));
+        assertEquals("0011", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 17 })));
         for (int i = -128; i <= 127; i++) {
             final byte test[] = { (byte) i, (byte) i };
-            assertArrayEquals(test, 
Base16.decodeBase16(Base16.encodeBase16(test)));
+            assertArrayEquals(test, new Base16().decode(new 
Base16().encode(test)));
         }
     }
 
     @Test
     public void testSingletons() {
-        assertEquals("00", new String(Base16.encodeBase16(new byte[] { (byte) 
0 })));
-        assertEquals("01", new String(Base16.encodeBase16(new byte[] { (byte) 
1 })));
-        assertEquals("02", new String(Base16.encodeBase16(new byte[] { (byte) 
2 })));
-        assertEquals("03", new String(Base16.encodeBase16(new byte[] { (byte) 
3 })));
-        assertEquals("04", new String(Base16.encodeBase16(new byte[] { (byte) 
4 })));
-        assertEquals("05", new String(Base16.encodeBase16(new byte[] { (byte) 
5 })));
-        assertEquals("06", new String(Base16.encodeBase16(new byte[] { (byte) 
6 })));
-        assertEquals("07", new String(Base16.encodeBase16(new byte[] { (byte) 
7 })));
-        assertEquals("08", new String(Base16.encodeBase16(new byte[] { (byte) 
8 })));
-        assertEquals("09", new String(Base16.encodeBase16(new byte[] { (byte) 
9 })));
-        assertEquals("0a", new String(Base16.encodeBase16(new byte[] { (byte) 
10 })));
-        assertEquals("0b", new String(Base16.encodeBase16(new byte[] { (byte) 
11 })));
-        assertEquals("0c", new String(Base16.encodeBase16(new byte[] { (byte) 
12 })));
-        assertEquals("0d", new String(Base16.encodeBase16(new byte[] { (byte) 
13 })));
-        assertEquals("0e", new String(Base16.encodeBase16(new byte[] { (byte) 
14 })));
-        assertEquals("0f", new String(Base16.encodeBase16(new byte[] { (byte) 
15 })));
-        assertEquals("10", new String(Base16.encodeBase16(new byte[] { (byte) 
16 })));
-        assertEquals("11", new String(Base16.encodeBase16(new byte[] { (byte) 
17 })));
-        assertEquals("12", new String(Base16.encodeBase16(new byte[] { (byte) 
18 })));
-        assertEquals("13", new String(Base16.encodeBase16(new byte[] { (byte) 
19 })));
-        assertEquals("14", new String(Base16.encodeBase16(new byte[] { (byte) 
20 })));
-        assertEquals("15", new String(Base16.encodeBase16(new byte[] { (byte) 
21 })));
-        assertEquals("16", new String(Base16.encodeBase16(new byte[] { (byte) 
22 })));
-        assertEquals("17", new String(Base16.encodeBase16(new byte[] { (byte) 
23 })));
-        assertEquals("18", new String(Base16.encodeBase16(new byte[] { (byte) 
24 })));
-        assertEquals("19", new String(Base16.encodeBase16(new byte[] { (byte) 
25 })));
-        assertEquals("1a", new String(Base16.encodeBase16(new byte[] { (byte) 
26 })));
-        assertEquals("1b", new String(Base16.encodeBase16(new byte[] { (byte) 
27 })));
-        assertEquals("1c", new String(Base16.encodeBase16(new byte[] { (byte) 
28 })));
-        assertEquals("1d", new String(Base16.encodeBase16(new byte[] { (byte) 
29 })));
-        assertEquals("1e", new String(Base16.encodeBase16(new byte[] { (byte) 
30 })));
-        assertEquals("1f", new String(Base16.encodeBase16(new byte[] { (byte) 
31 })));
-        assertEquals("20", new String(Base16.encodeBase16(new byte[] { (byte) 
32 })));
-        assertEquals("21", new String(Base16.encodeBase16(new byte[] { (byte) 
33 })));
-        assertEquals("22", new String(Base16.encodeBase16(new byte[] { (byte) 
34 })));
-        assertEquals("23", new String(Base16.encodeBase16(new byte[] { (byte) 
35 })));
-        assertEquals("24", new String(Base16.encodeBase16(new byte[] { (byte) 
36 })));
-        assertEquals("25", new String(Base16.encodeBase16(new byte[] { (byte) 
37 })));
-        assertEquals("26", new String(Base16.encodeBase16(new byte[] { (byte) 
38 })));
-        assertEquals("27", new String(Base16.encodeBase16(new byte[] { (byte) 
39 })));
-        assertEquals("28", new String(Base16.encodeBase16(new byte[] { (byte) 
40 })));
-        assertEquals("29", new String(Base16.encodeBase16(new byte[] { (byte) 
41 })));
-        assertEquals("2a", new String(Base16.encodeBase16(new byte[] { (byte) 
42 })));
-        assertEquals("2b", new String(Base16.encodeBase16(new byte[] { (byte) 
43 })));
-        assertEquals("2c", new String(Base16.encodeBase16(new byte[] { (byte) 
44 })));
-        assertEquals("2d", new String(Base16.encodeBase16(new byte[] { (byte) 
45 })));
-        assertEquals("2e", new String(Base16.encodeBase16(new byte[] { (byte) 
46 })));
-        assertEquals("2f", new String(Base16.encodeBase16(new byte[] { (byte) 
47 })));
-        assertEquals("30", new String(Base16.encodeBase16(new byte[] { (byte) 
48 })));
-        assertEquals("31", new String(Base16.encodeBase16(new byte[] { (byte) 
49 })));
-        assertEquals("32", new String(Base16.encodeBase16(new byte[] { (byte) 
50 })));
-        assertEquals("33", new String(Base16.encodeBase16(new byte[] { (byte) 
51 })));
-        assertEquals("34", new String(Base16.encodeBase16(new byte[] { (byte) 
52 })));
-        assertEquals("35", new String(Base16.encodeBase16(new byte[] { (byte) 
53 })));
-        assertEquals("36", new String(Base16.encodeBase16(new byte[] { (byte) 
54 })));
-        assertEquals("37", new String(Base16.encodeBase16(new byte[] { (byte) 
55 })));
-        assertEquals("38", new String(Base16.encodeBase16(new byte[] { (byte) 
56 })));
-        assertEquals("39", new String(Base16.encodeBase16(new byte[] { (byte) 
57 })));
-        assertEquals("3a", new String(Base16.encodeBase16(new byte[] { (byte) 
58 })));
-        assertEquals("3b", new String(Base16.encodeBase16(new byte[] { (byte) 
59 })));
-        assertEquals("3c", new String(Base16.encodeBase16(new byte[] { (byte) 
60 })));
-        assertEquals("3d", new String(Base16.encodeBase16(new byte[] { (byte) 
61 })));
-        assertEquals("3e", new String(Base16.encodeBase16(new byte[] { (byte) 
62 })));
-        assertEquals("3f", new String(Base16.encodeBase16(new byte[] { (byte) 
63 })));
-        assertEquals("40", new String(Base16.encodeBase16(new byte[] { (byte) 
64 })));
-        assertEquals("41", new String(Base16.encodeBase16(new byte[] { (byte) 
65 })));
-        assertEquals("42", new String(Base16.encodeBase16(new byte[] { (byte) 
66 })));
-        assertEquals("43", new String(Base16.encodeBase16(new byte[] { (byte) 
67 })));
-        assertEquals("44", new String(Base16.encodeBase16(new byte[] { (byte) 
68 })));
-        assertEquals("45", new String(Base16.encodeBase16(new byte[] { (byte) 
69 })));
-        assertEquals("46", new String(Base16.encodeBase16(new byte[] { (byte) 
70 })));
-        assertEquals("47", new String(Base16.encodeBase16(new byte[] { (byte) 
71 })));
-        assertEquals("48", new String(Base16.encodeBase16(new byte[] { (byte) 
72 })));
-        assertEquals("49", new String(Base16.encodeBase16(new byte[] { (byte) 
73 })));
-        assertEquals("4a", new String(Base16.encodeBase16(new byte[] { (byte) 
74 })));
-        assertEquals("4b", new String(Base16.encodeBase16(new byte[] { (byte) 
75 })));
-        assertEquals("4c", new String(Base16.encodeBase16(new byte[] { (byte) 
76 })));
-        assertEquals("4d", new String(Base16.encodeBase16(new byte[] { (byte) 
77 })));
-        assertEquals("4e", new String(Base16.encodeBase16(new byte[] { (byte) 
78 })));
-        assertEquals("4f", new String(Base16.encodeBase16(new byte[] { (byte) 
79 })));
-        assertEquals("50", new String(Base16.encodeBase16(new byte[] { (byte) 
80 })));
-        assertEquals("51", new String(Base16.encodeBase16(new byte[] { (byte) 
81 })));
-        assertEquals("52", new String(Base16.encodeBase16(new byte[] { (byte) 
82 })));
-        assertEquals("53", new String(Base16.encodeBase16(new byte[] { (byte) 
83 })));
-        assertEquals("54", new String(Base16.encodeBase16(new byte[] { (byte) 
84 })));
-        assertEquals("55", new String(Base16.encodeBase16(new byte[] { (byte) 
85 })));
-        assertEquals("56", new String(Base16.encodeBase16(new byte[] { (byte) 
86 })));
-        assertEquals("57", new String(Base16.encodeBase16(new byte[] { (byte) 
87 })));
-        assertEquals("58", new String(Base16.encodeBase16(new byte[] { (byte) 
88 })));
-        assertEquals("59", new String(Base16.encodeBase16(new byte[] { (byte) 
89 })));
-        assertEquals("5a", new String(Base16.encodeBase16(new byte[] { (byte) 
90 })));
-        assertEquals("5b", new String(Base16.encodeBase16(new byte[] { (byte) 
91 })));
-        assertEquals("5c", new String(Base16.encodeBase16(new byte[] { (byte) 
92 })));
-        assertEquals("5d", new String(Base16.encodeBase16(new byte[] { (byte) 
93 })));
-        assertEquals("5e", new String(Base16.encodeBase16(new byte[] { (byte) 
94 })));
-        assertEquals("5f", new String(Base16.encodeBase16(new byte[] { (byte) 
95 })));
-        assertEquals("60", new String(Base16.encodeBase16(new byte[] { (byte) 
96 })));
-        assertEquals("61", new String(Base16.encodeBase16(new byte[] { (byte) 
97 })));
-        assertEquals("62", new String(Base16.encodeBase16(new byte[] { (byte) 
98 })));
-        assertEquals("63", new String(Base16.encodeBase16(new byte[] { (byte) 
99 })));
-        assertEquals("64", new String(Base16.encodeBase16(new byte[] { (byte) 
100 })));
-        assertEquals("65", new String(Base16.encodeBase16(new byte[] { (byte) 
101 })));
-        assertEquals("66", new String(Base16.encodeBase16(new byte[] { (byte) 
102 })));
-        assertEquals("67", new String(Base16.encodeBase16(new byte[] { (byte) 
103 })));
-        assertEquals("68", new String(Base16.encodeBase16(new byte[] { (byte) 
104 })));
+        assertEquals("00", new String(new Base16().encode(new byte[] { (byte) 
0 })));
+        assertEquals("01", new String(new Base16().encode(new byte[] { (byte) 
1 })));
+        assertEquals("02", new String(new Base16().encode(new byte[] { (byte) 
2 })));
+        assertEquals("03", new String(new Base16().encode(new byte[] { (byte) 
3 })));
+        assertEquals("04", new String(new Base16().encode(new byte[] { (byte) 
4 })));
+        assertEquals("05", new String(new Base16().encode(new byte[] { (byte) 
5 })));
+        assertEquals("06", new String(new Base16().encode(new byte[] { (byte) 
6 })));
+        assertEquals("07", new String(new Base16().encode(new byte[] { (byte) 
7 })));
+        assertEquals("08", new String(new Base16().encode(new byte[] { (byte) 
8 })));
+        assertEquals("09", new String(new Base16().encode(new byte[] { (byte) 
9 })));
+        assertEquals("0A", new String(new Base16().encode(new byte[] { (byte) 
10 })));
+        assertEquals("0B", new String(new Base16().encode(new byte[] { (byte) 
11 })));
+        assertEquals("0C", new String(new Base16().encode(new byte[] { (byte) 
12 })));
+        assertEquals("0D", new String(new Base16().encode(new byte[] { (byte) 
13 })));
+        assertEquals("0E", new String(new Base16().encode(new byte[] { (byte) 
14 })));
+        assertEquals("0F", new String(new Base16().encode(new byte[] { (byte) 
15 })));
+        assertEquals("10", new String(new Base16().encode(new byte[] { (byte) 
16 })));
+        assertEquals("11", new String(new Base16().encode(new byte[] { (byte) 
17 })));
+        assertEquals("12", new String(new Base16().encode(new byte[] { (byte) 
18 })));
+        assertEquals("13", new String(new Base16().encode(new byte[] { (byte) 
19 })));
+        assertEquals("14", new String(new Base16().encode(new byte[] { (byte) 
20 })));
+        assertEquals("15", new String(new Base16().encode(new byte[] { (byte) 
21 })));
+        assertEquals("16", new String(new Base16().encode(new byte[] { (byte) 
22 })));
+        assertEquals("17", new String(new Base16().encode(new byte[] { (byte) 
23 })));
+        assertEquals("18", new String(new Base16().encode(new byte[] { (byte) 
24 })));
+        assertEquals("19", new String(new Base16().encode(new byte[] { (byte) 
25 })));
+        assertEquals("1A", new String(new Base16().encode(new byte[] { (byte) 
26 })));
+        assertEquals("1B", new String(new Base16().encode(new byte[] { (byte) 
27 })));
+        assertEquals("1C", new String(new Base16().encode(new byte[] { (byte) 
28 })));
+        assertEquals("1D", new String(new Base16().encode(new byte[] { (byte) 
29 })));
+        assertEquals("1E", new String(new Base16().encode(new byte[] { (byte) 
30 })));
+        assertEquals("1F", new String(new Base16().encode(new byte[] { (byte) 
31 })));
+        assertEquals("20", new String(new Base16().encode(new byte[] { (byte) 
32 })));
+        assertEquals("21", new String(new Base16().encode(new byte[] { (byte) 
33 })));
+        assertEquals("22", new String(new Base16().encode(new byte[] { (byte) 
34 })));
+        assertEquals("23", new String(new Base16().encode(new byte[] { (byte) 
35 })));
+        assertEquals("24", new String(new Base16().encode(new byte[] { (byte) 
36 })));
+        assertEquals("25", new String(new Base16().encode(new byte[] { (byte) 
37 })));
+        assertEquals("26", new String(new Base16().encode(new byte[] { (byte) 
38 })));
+        assertEquals("27", new String(new Base16().encode(new byte[] { (byte) 
39 })));
+        assertEquals("28", new String(new Base16().encode(new byte[] { (byte) 
40 })));
+        assertEquals("29", new String(new Base16().encode(new byte[] { (byte) 
41 })));
+        assertEquals("2A", new String(new Base16().encode(new byte[] { (byte) 
42 })));
+        assertEquals("2B", new String(new Base16().encode(new byte[] { (byte) 
43 })));
+        assertEquals("2C", new String(new Base16().encode(new byte[] { (byte) 
44 })));
+        assertEquals("2D", new String(new Base16().encode(new byte[] { (byte) 
45 })));
+        assertEquals("2E", new String(new Base16().encode(new byte[] { (byte) 
46 })));
+        assertEquals("2F", new String(new Base16().encode(new byte[] { (byte) 
47 })));
+        assertEquals("30", new String(new Base16().encode(new byte[] { (byte) 
48 })));
+        assertEquals("31", new String(new Base16().encode(new byte[] { (byte) 
49 })));
+        assertEquals("32", new String(new Base16().encode(new byte[] { (byte) 
50 })));
+        assertEquals("33", new String(new Base16().encode(new byte[] { (byte) 
51 })));
+        assertEquals("34", new String(new Base16().encode(new byte[] { (byte) 
52 })));
+        assertEquals("35", new String(new Base16().encode(new byte[] { (byte) 
53 })));
+        assertEquals("36", new String(new Base16().encode(new byte[] { (byte) 
54 })));
+        assertEquals("37", new String(new Base16().encode(new byte[] { (byte) 
55 })));
+        assertEquals("38", new String(new Base16().encode(new byte[] { (byte) 
56 })));
+        assertEquals("39", new String(new Base16().encode(new byte[] { (byte) 
57 })));
+        assertEquals("3A", new String(new Base16().encode(new byte[] { (byte) 
58 })));
+        assertEquals("3B", new String(new Base16().encode(new byte[] { (byte) 
59 })));
+        assertEquals("3C", new String(new Base16().encode(new byte[] { (byte) 
60 })));
+        assertEquals("3D", new String(new Base16().encode(new byte[] { (byte) 
61 })));
+        assertEquals("3E", new String(new Base16().encode(new byte[] { (byte) 
62 })));
+        assertEquals("3F", new String(new Base16().encode(new byte[] { (byte) 
63 })));
+        assertEquals("40", new String(new Base16().encode(new byte[] { (byte) 
64 })));
+        assertEquals("41", new String(new Base16().encode(new byte[] { (byte) 
65 })));
+        assertEquals("42", new String(new Base16().encode(new byte[] { (byte) 
66 })));
+        assertEquals("43", new String(new Base16().encode(new byte[] { (byte) 
67 })));
+        assertEquals("44", new String(new Base16().encode(new byte[] { (byte) 
68 })));
+        assertEquals("45", new String(new Base16().encode(new byte[] { (byte) 
69 })));
+        assertEquals("46", new String(new Base16().encode(new byte[] { (byte) 
70 })));
+        assertEquals("47", new String(new Base16().encode(new byte[] { (byte) 
71 })));
+        assertEquals("48", new String(new Base16().encode(new byte[] { (byte) 
72 })));
+        assertEquals("49", new String(new Base16().encode(new byte[] { (byte) 
73 })));
+        assertEquals("4A", new String(new Base16().encode(new byte[] { (byte) 
74 })));
+        assertEquals("4B", new String(new Base16().encode(new byte[] { (byte) 
75 })));
+        assertEquals("4C", new String(new Base16().encode(new byte[] { (byte) 
76 })));
+        assertEquals("4D", new String(new Base16().encode(new byte[] { (byte) 
77 })));
+        assertEquals("4E", new String(new Base16().encode(new byte[] { (byte) 
78 })));
+        assertEquals("4F", new String(new Base16().encode(new byte[] { (byte) 
79 })));
+        assertEquals("50", new String(new Base16().encode(new byte[] { (byte) 
80 })));
+        assertEquals("51", new String(new Base16().encode(new byte[] { (byte) 
81 })));
+        assertEquals("52", new String(new Base16().encode(new byte[] { (byte) 
82 })));
+        assertEquals("53", new String(new Base16().encode(new byte[] { (byte) 
83 })));
+        assertEquals("54", new String(new Base16().encode(new byte[] { (byte) 
84 })));
+        assertEquals("55", new String(new Base16().encode(new byte[] { (byte) 
85 })));
+        assertEquals("56", new String(new Base16().encode(new byte[] { (byte) 
86 })));
+        assertEquals("57", new String(new Base16().encode(new byte[] { (byte) 
87 })));
+        assertEquals("58", new String(new Base16().encode(new byte[] { (byte) 
88 })));
+        assertEquals("59", new String(new Base16().encode(new byte[] { (byte) 
89 })));
+        assertEquals("5A", new String(new Base16().encode(new byte[] { (byte) 
90 })));
+        assertEquals("5B", new String(new Base16().encode(new byte[] { (byte) 
91 })));
+        assertEquals("5C", new String(new Base16().encode(new byte[] { (byte) 
92 })));
+        assertEquals("5D", new String(new Base16().encode(new byte[] { (byte) 
93 })));
+        assertEquals("5E", new String(new Base16().encode(new byte[] { (byte) 
94 })));
+        assertEquals("5F", new String(new Base16().encode(new byte[] { (byte) 
95 })));
+        assertEquals("60", new String(new Base16().encode(new byte[] { (byte) 
96 })));
+        assertEquals("61", new String(new Base16().encode(new byte[] { (byte) 
97 })));
+        assertEquals("62", new String(new Base16().encode(new byte[] { (byte) 
98 })));
+        assertEquals("63", new String(new Base16().encode(new byte[] { (byte) 
99 })));
+        assertEquals("64", new String(new Base16().encode(new byte[] { (byte) 
100 })));
+        assertEquals("65", new String(new Base16().encode(new byte[] { (byte) 
101 })));
+        assertEquals("66", new String(new Base16().encode(new byte[] { (byte) 
102 })));
+        assertEquals("67", new String(new Base16().encode(new byte[] { (byte) 
103 })));
+        assertEquals("68", new String(new Base16().encode(new byte[] { (byte) 
104 })));
         for (int i = -128; i <= 127; i++) {
             final byte test[] = { (byte) i };
-            assertTrue(Arrays.equals(test, 
Base16.decodeBase16(Base16.encodeBase16(test))));
+            assertTrue(Arrays.equals(test, new Base16().decode(new 
Base16().encode(test))));
         }
     }
 
     @Test
     public void testTriplets() {
-        assertEquals("000000", new String(Base16.encodeBase16(new byte[] { 
(byte) 0, (byte) 0, (byte) 0 })));
-        assertEquals("000001", new String(Base16.encodeBase16(new byte[] { 
(byte) 0, (byte) 0, (byte) 1 })));
-        assertEquals("000002", new String(Base16.encodeBase16(new byte[] { 
(byte) 0, (byte) 0, (byte) 2 })));
-        assertEquals("000003", new String(Base16.encodeBase16(new byte[] { 
(byte) 0, (byte) 0, (byte) 3 })));
-        assertEquals("000004", new String(Base16.encodeBase16(new byte[] { 
(byte) 0, (byte) 0, (byte) 4 })));
-        assertEquals("000005", new String(Base16.encodeBase16(new byte[] { 
(byte) 0, (byte) 0, (byte) 5 })));
-        assertEquals("000006", new String(Base16.encodeBase16(new byte[] { 
(byte) 0, (byte) 0, (byte) 6 })));
-        assertEquals("000007", new String(Base16.encodeBase16(new byte[] { 
(byte) 0, (byte) 0, (byte) 7 })));
-        assertEquals("000008", new String(Base16.encodeBase16(new byte[] { 
(byte) 0, (byte) 0, (byte) 8 })));
-        assertEquals("000009", new String(Base16.encodeBase16(new byte[] { 
(byte) 0, (byte) 0, (byte) 9 })));
-        assertEquals("00000a", new String(Base16.encodeBase16(new byte[] { 
(byte) 0, (byte) 0, (byte) 10 })));
-        assertEquals("00000b", new String(Base16.encodeBase16(new byte[] { 
(byte) 0, (byte) 0, (byte) 11 })));
-        assertEquals("00000c", new String(Base16.encodeBase16(new byte[] { 
(byte) 0, (byte) 0, (byte) 12 })));
-        assertEquals("00000d", new String(Base16.encodeBase16(new byte[] { 
(byte) 0, (byte) 0, (byte) 13 })));
-        assertEquals("00000e", new String(Base16.encodeBase16(new byte[] { 
(byte) 0, (byte) 0, (byte) 14 })));
-        assertEquals("00000f", new String(Base16.encodeBase16(new byte[] { 
(byte) 0, (byte) 0, (byte) 15 })));
+        assertEquals("000000", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 0, (byte) 0 })));
+        assertEquals("000001", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 0, (byte) 1 })));
+        assertEquals("000002", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 0, (byte) 2 })));
+        assertEquals("000003", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 0, (byte) 3 })));
+        assertEquals("000004", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 0, (byte) 4 })));
+        assertEquals("000005", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 0, (byte) 5 })));
+        assertEquals("000006", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 0, (byte) 6 })));
+        assertEquals("000007", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 0, (byte) 7 })));
+        assertEquals("000008", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 0, (byte) 8 })));
+        assertEquals("000009", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 0, (byte) 9 })));
+        assertEquals("00000A", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 0, (byte) 10 })));
+        assertEquals("00000B", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 0, (byte) 11 })));
+        assertEquals("00000C", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 0, (byte) 12 })));
+        assertEquals("00000D", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 0, (byte) 13 })));
+        assertEquals("00000E", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 0, (byte) 14 })));
+        assertEquals("00000F", new String(new Base16().encode(new byte[] { 
(byte) 0, (byte) 0, (byte) 15 })));
     }
 
     @Test
@@ -485,30 +439,30 @@ public class Base16Test {
         final byte[] b2 = new byte[0];
         final byte[] b3 = null;
 
-        assertEquals("byteToString Hello World", "48656c6c6f20576f726c64", 
Base16.encodeToString(b1));
-        assertEquals("byteToString static Hello World", 
"48656c6c6f20576f726c64", StringUtils.newStringUtf8(Base16.encodeBase16(b1)));
+        assertEquals("byteToString Hello World", "48656C6C6F20576F726C64", 
Base16.encodeToString(b1));
+        assertEquals("byteToString static Hello World", 
"48656C6C6F20576F726C64", StringUtils.newStringUtf8(new Base16().encode(b1)));
         assertEquals("byteToString \"\"", "", Base16.encodeToString(b2));
-        assertEquals("byteToString static \"\"", "", 
StringUtils.newStringUtf8(Base16.encodeBase16(b2)));
+        assertEquals("byteToString static \"\"", "", 
StringUtils.newStringUtf8(new Base16().encode(b2)));
         assertEquals("byteToString null", null, Base16.encodeToString(b3));
-        assertEquals("byteToString static null", null, 
StringUtils.newStringUtf8(Base16.encodeBase16(b3)));
+        assertEquals("byteToString static null", null, 
StringUtils.newStringUtf8(new Base16().encode(b3)));
     }
 
     @Test
     public void testStringToByteVariations() throws DecoderException {
         final Base16 Base16 = new Base16();
-        final String s1 = "48656c6c6f20576f726c64";
+        final String s1 = "48656C6C6F20576F726C64";
         final String s2 = "";
         final String s3 = null;
 
         assertEquals("StringToByte Hello World", "Hello World", 
StringUtils.newStringUtf8(Base16.decode(s1)));
         assertEquals("StringToByte Hello World", "Hello World",
-                StringUtils.newStringUtf8((byte[]) Base16.decode((Object) 
s1)));
+                StringUtils.newStringUtf8((byte[]) new 
Base16().decode((Object) s1)));
         assertEquals("StringToByte static Hello World", "Hello World",
-                StringUtils.newStringUtf8(Base16.decodeBase16(s1)));
-        assertEquals("StringToByte \"\"", "", 
StringUtils.newStringUtf8(Base16.decode(s2)));
-        assertEquals("StringToByte static \"\"", "", 
StringUtils.newStringUtf8(Base16.decodeBase16(s2)));
-        assertEquals("StringToByte null", null, 
StringUtils.newStringUtf8(Base16.decode(s3)));
-        assertEquals("StringToByte static null", null, 
StringUtils.newStringUtf8(Base16.decodeBase16(s3)));
+                StringUtils.newStringUtf8(new Base16().decode(s1)));
+        assertEquals("StringToByte \"\"", "", StringUtils.newStringUtf8(new 
Base16().decode(s2)));
+        assertEquals("StringToByte static \"\"", "", 
StringUtils.newStringUtf8(new Base16().decode(s2)));
+        assertEquals("StringToByte null", null, StringUtils.newStringUtf8(new 
Base16().decode(s3)));
+        assertEquals("StringToByte static null", null, 
StringUtils.newStringUtf8(new Base16().decode(s3)));
     }
 
     private String toString(final byte[] data) {
@@ -523,14 +477,13 @@ public class Base16Test {
     }
 
     /**
-     * Test for CODEC-265: Encode a 1GiB file.
+     * Test for CODEC-265: Encode a ~1GiB file.
      *
      * @see <a 
href="https://issues.apache.org/jira/projects/CODEC/issues/CODEC-265";>CODEC-265</a>
      */
-    @Test(expected = IllegalArgumentException.class)
     public void testCodec265_over() {
-        // 1GiB file to encode: 2^30 bytes
-        final int size1GiB = 1 << 30;
+        // almost 1GiB file to encode: 2^29 bytes
+        final int size1GiB = 1 << 29;
 
         // Expecting a size of 2 output bytes per 1 input byte
         final int blocks = size1GiB;
@@ -551,14 +504,24 @@ public class Base16Test {
         Assume.assumeTrue("Not enough free memory for the test", 
presumableFreeMemory > estimatedMemory);
 
         final byte[] bytes = new byte[size1GiB];
-        final byte[] encoded = Base16.encodeBase16(bytes);
+        final byte[] encoded = new Base16().encode(bytes);
         assertEquals(expectedLength, encoded.length);
     }
 
     @Test
     public void testIsInAlphabet() {
+        // invalid bounds
+        Base16 b16 = new Base16(true);
+        assertFalse(b16.isInAlphabet((byte)0));
+        assertFalse(b16.isInAlphabet((byte)1));
+        assertFalse(b16.isInAlphabet((byte)-1));
+        assertFalse(b16.isInAlphabet((byte)-15));
+        assertFalse(b16.isInAlphabet((byte)-16));
+        assertFalse(b16.isInAlphabet((byte)128));
+        assertFalse(b16.isInAlphabet((byte)255));
+
         // lower-case
-        Base16 b16 = new Base16(true, CHARSET_UTF8);
+        b16 = new Base16(true);
         for (char c = '0'; c <= '9'; c++) {
             assertTrue(b16.isInAlphabet((byte) c));
         }
@@ -574,7 +537,7 @@ public class Base16Test {
         assertFalse(b16.isInAlphabet((byte) ('z' + 1)));
 
         // upper-case
-        b16 = new Base16(false, CHARSET_UTF8);
+        b16 = new Base16(false);
         for (char c = '0'; c <= '9'; c++) {
             assertTrue(b16.isInAlphabet((byte) c));
         }
@@ -592,7 +555,7 @@ public class Base16Test {
 
     @Test
     public void testDecodeSingleBytes() {
-        final String encoded = "556e74696c206e6578742074696d6521";
+        final String encoded = "556E74696C206E6578742074696D6521";
 
         final BaseNCodec.Context context = new BaseNCodec.Context();
         final Base16 b16 = new Base16();
@@ -620,11 +583,31 @@ public class Base16Test {
         assertEquals("Until next time!", decoded);
     }
 
+    @Test
+    public void testDecodeSingleBytesOptimisation() {
+        final BaseNCodec.Context context = new BaseNCodec.Context();
+        context.ibitWorkArea = 0;
+
+        final byte[] data = new byte[1];
+
+        final Base16 b16 = new Base16();
+
+        data[0] = (byte) 'E';
+        b16.decode(data, 0, 1, context);
+        assertEquals(69, context.ibitWorkArea);
+
+        data[0] = (byte) 'F';
+        b16.decode(data, 0, 1, context);
+        assertEquals(-1, context.ibitWorkArea);
+
+        assertEquals(-17, context.buffer[0]);
+    }
+
     @Test(expected=IllegalArgumentException.class)
     public void testStrictDecoding() {
         final String encoded = "aabbccdde";  // Note the trailing `e` which 
does not make up a hex-pair and so is only 1/2 byte
 
-        final Base16 b16 = new Base16(true, CHARSET_UTF8, CodecPolicy.STRICT);
+        final Base16 b16 = new Base16(true, CodecPolicy.STRICT);
         b16.decode(StringUtils.getBytesUtf8(encoded));
     }
 
@@ -632,7 +615,7 @@ public class Base16Test {
     public void testLenientDecoding() {
         final String encoded = "aabbccdde";  // Note the trailing `e` which 
does not make up a hex-pair and so is only 1/2 byte
 
-        final Base16 b16 = new Base16(true, CHARSET_UTF8, CodecPolicy.LENIENT);
+        final Base16 b16 = new Base16(true, CodecPolicy.LENIENT);
 
         final byte[] decoded = b16.decode(StringUtils.getBytesUtf8(encoded));
         assertArrayEquals(new byte[] {(byte)0xaa, (byte)0xbb, (byte)0xcc, 
(byte)0xdd}, decoded);

Reply via email to