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);