You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2023/10/23 12:39:23 UTC
[commons-codec] 01/05: Sort members
This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-codec.git
commit 931bb815b690b098936beca76c600f134027f1bd
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Mon Oct 23 08:33:20 2023 -0400
Sort members
---
.../org/apache/commons/codec/binary/Base64.java | 54 +-
.../apache/commons/codec/binary/BaseNCodec.java | 232 +--
.../java/org/apache/commons/codec/binary/Hex.java | 4 +-
.../java/org/apache/commons/codec/cli/Digest.java | 24 +-
.../org/apache/commons/codec/digest/Blake3.java | 670 ++++-----
.../org/apache/commons/codec/digest/HmacUtils.java | 212 +--
.../apache/commons/codec/digest/MurmurHash2.java | 136 +-
.../apache/commons/codec/digest/MurmurHash3.java | 1522 ++++++++++----------
.../org/apache/commons/codec/digest/UnixCrypt.java | 86 +-
.../org/apache/commons/codec/digest/XXHash32.java | 140 +-
.../commons/codec/language/ColognePhonetic.java | 90 +-
.../codec/language/DaitchMokotoffSoundex.java | 46 +-
.../commons/codec/language/DoubleMetaphone.java | 466 +++---
.../apache/commons/codec/language/Metaphone.java | 150 +-
.../org/apache/commons/codec/language/Nysiis.java | 6 +-
.../commons/codec/language/RefinedSoundex.java | 12 +-
.../org/apache/commons/codec/language/Soundex.java | 18 +-
.../codec/language/bm/BeiderMorseEncoder.java | 28 +-
.../org/apache/commons/codec/language/bm/Lang.java | 16 +-
.../commons/codec/language/bm/Languages.java | 172 +--
.../commons/codec/language/bm/PhoneticEngine.java | 80 +-
.../org/apache/commons/codec/language/bm/Rule.java | 48 +-
.../java/org/apache/commons/codec/net/BCodec.java | 188 +--
.../org/apache/commons/codec/net/PercentCodec.java | 198 +--
.../java/org/apache/commons/codec/net/QCodec.java | 192 +--
.../commons/codec/net/QuotedPrintableCodec.java | 444 +++---
.../org/apache/commons/codec/net/RFC1522Codec.java | 134 +-
.../org/apache/commons/codec/net/URLCodec.java | 220 +--
.../org/apache/commons/codec/CharsetsTest.java | 12 +-
.../commons/codec/StringEncoderComparatorTest.java | 18 +-
.../apache/commons/codec/binary/Base16Test.java | 388 ++---
.../codec/binary/Base32InputStreamTest.java | 124 +-
.../codec/binary/Base32OutputStreamTest.java | 70 +-
.../apache/commons/codec/binary/Base32Test.java | 278 ++--
.../commons/codec/binary/Base64Codec13Test.java | 496 +++----
.../codec/binary/Base64InputStreamTest.java | 248 ++--
.../codec/binary/Base64OutputStreamTest.java | 100 +-
.../apache/commons/codec/binary/Base64Test.java | 610 ++++----
.../commons/codec/binary/BaseNCodecTest.java | 446 +++---
.../apache/commons/codec/binary/BaseNTestData.java | 108 +-
.../commons/codec/binary/BinaryCodecTest.java | 714 ++++-----
.../codec/binary/CharSequenceUtilsTest.java | 66 +-
.../org/apache/commons/codec/binary/HexTest.java | 272 ++--
.../commons/codec/binary/StringUtilsTest.java | 112 +-
.../apache/commons/codec/digest/Apr1CryptTest.java | 42 +-
.../org/apache/commons/codec/digest/B64Test.java | 12 +-
.../apache/commons/codec/digest/Blake3Test.java | 8 +-
.../codec/digest/Blake3TestVectorsTest.java | 44 +-
.../org/apache/commons/codec/digest/CryptTest.java | 14 +-
.../apache/commons/codec/digest/Md5CryptTest.java | 26 +-
.../commons/codec/digest/MurmurHash2Test.java | 32 +-
.../commons/codec/digest/MurmurHash3Test.java | 1092 +++++++-------
.../commons/codec/digest/PureJavaCrc32CTest.java | 36 +-
.../commons/codec/digest/PureJavaCrc32Test.java | 478 +++---
.../commons/codec/digest/Sha256CryptTest.java | 60 +-
.../commons/codec/digest/Sha512CryptTest.java | 58 +-
.../apache/commons/codec/digest/UnixCryptTest.java | 42 +-
.../apache/commons/codec/digest/XXHash32Test.java | 56 +-
.../codec/language/ColognePhoneticTest.java | 60 +-
.../codec/language/DaitchMokotoffSoundexTest.java | 8 +-
.../language/MatchRatingApproachEncoderTest.java | 374 ++---
.../commons/codec/language/MetaphoneTest.java | 144 +-
.../apache/commons/codec/language/SoundexTest.java | 58 +-
.../bm/CacheSubSequencePerformanceTest.java | 58 +-
.../language/bm/PhoneticEngineRegressionTest.java | 214 +--
.../org/apache/commons/codec/net/BCodecTest.java | 112 +-
.../commons/codec/net/CustomRFC1522Codec.java | 12 +-
.../org/apache/commons/codec/net/QCodecTest.java | 142 +-
.../codec/net/QuotedPrintableCodecTest.java | 202 +--
.../apache/commons/codec/net/RFC1522CodecTest.java | 14 +-
.../org/apache/commons/codec/net/URLCodecTest.java | 188 +--
71 files changed, 6618 insertions(+), 6618 deletions(-)
diff --git a/src/main/java/org/apache/commons/codec/binary/Base64.java b/src/main/java/org/apache/commons/codec/binary/Base64.java
index b856469d..3521edc2 100644
--- a/src/main/java/org/apache/commons/codec/binary/Base64.java
+++ b/src/main/java/org/apache/commons/codec/binary/Base64.java
@@ -132,33 +132,6 @@ public class Base64 extends BaseNCodec {
/** Mask used to extract 2 bits, used when decoding final trailing character. */
private static final int MASK_2BITS = 0x3;
- /**
- * Encode table to use: either STANDARD or URL_SAFE. Note: the DECODE_TABLE above remains static because it is able
- * to decode both STANDARD and URL_SAFE streams, but the encodeTable must be a member variable so we can switch
- * between the two modes.
- */
- private final byte[] encodeTable;
-
- /** Only one decode table currently; keep for consistency with Base32 code. */
- private final byte[] decodeTable = DECODE_TABLE;
-
- /**
- * Line separator for encoding. Not used when decoding. Only used if lineLength > 0.
- */
- private final byte[] lineSeparator;
-
- /**
- * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
- * {@code decodeSize = 3 + lineSeparator.length;}
- */
- private final int decodeSize;
-
- /**
- * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
- * {@code encodeSize = 4 + lineSeparator.length;}
- */
- private final int encodeSize;
-
/**
* Decodes Base64 data into octets.
* <p>
@@ -441,6 +414,33 @@ public class Base64 extends BaseNCodec {
return resizedBytes;
}
+ /**
+ * Encode table to use: either STANDARD or URL_SAFE. Note: the DECODE_TABLE above remains static because it is able
+ * to decode both STANDARD and URL_SAFE streams, but the encodeTable must be a member variable so we can switch
+ * between the two modes.
+ */
+ private final byte[] encodeTable;
+
+ /** Only one decode table currently; keep for consistency with Base32 code. */
+ private final byte[] decodeTable = DECODE_TABLE;
+
+ /**
+ * Line separator for encoding. Not used when decoding. Only used if lineLength > 0.
+ */
+ private final byte[] lineSeparator;
+
+ /**
+ * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
+ * {@code decodeSize = 3 + lineSeparator.length;}
+ */
+ private final int decodeSize;
+
+ /**
+ * Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
+ * {@code encodeSize = 4 + lineSeparator.length;}
+ */
+ private final int encodeSize;
+
/**
* Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
* <p>
diff --git a/src/main/java/org/apache/commons/codec/binary/BaseNCodec.java b/src/main/java/org/apache/commons/codec/binary/BaseNCodec.java
index 551befcd..ef8071de 100644
--- a/src/main/java/org/apache/commons/codec/binary/BaseNCodec.java
+++ b/src/main/java/org/apache/commons/codec/binary/BaseNCodec.java
@@ -51,6 +51,74 @@ import org.apache.commons.codec.EncoderException;
*/
public abstract class BaseNCodec implements BinaryEncoder, BinaryDecoder {
+ /**
+ * Holds thread context so classes can be thread-safe.
+ *
+ * This class is not itself thread-safe; each thread must allocate its own copy.
+ *
+ * @since 1.7
+ */
+ static class Context {
+
+ /**
+ * Placeholder for the bytes we're dealing with for our based logic.
+ * Bitwise operations store and extract the encoding or decoding from this variable.
+ */
+ int ibitWorkArea;
+
+ /**
+ * Placeholder for the bytes we're dealing with for our based logic.
+ * Bitwise operations store and extract the encoding or decoding from this variable.
+ */
+ long lbitWorkArea;
+
+ /**
+ * Buffer for streaming.
+ */
+ byte[] buffer;
+
+ /**
+ * Position where next character should be written in the buffer.
+ */
+ int pos;
+
+ /**
+ * Position where next character should be read from the buffer.
+ */
+ int readPos;
+
+ /**
+ * Boolean flag to indicate the EOF has been reached. Once EOF has been reached, this object becomes useless,
+ * and must be thrown away.
+ */
+ boolean eof;
+
+ /**
+ * Variable tracks how many characters have been written to the current line. Only used when encoding. We use
+ * it to make sure each encoded line never goes beyond lineLength (if lineLength > 0).
+ */
+ int currentLinePos;
+
+ /**
+ * Writes to the buffer only occur after every 3/5 reads when encoding, and every 4/8 reads when decoding. This
+ * variable helps track that.
+ */
+ int modulus;
+
+ /**
+ * Returns a String useful for debugging (especially within a debugger.)
+ *
+ * @return a String useful for debugging.
+ */
+ @SuppressWarnings("boxing") // OK to ignore boxing here
+ @Override
+ public String toString() {
+ return String.format("%s[buffer=%s, currentLinePos=%s, eof=%s, ibitWorkArea=%s, lbitWorkArea=%s, " +
+ "modulus=%s, pos=%s, readPos=%s]", this.getClass().getSimpleName(), Arrays.toString(buffer),
+ currentLinePos, eof, ibitWorkArea, lbitWorkArea, modulus, pos, readPos);
+ }
+ }
+
/**
* EOF
*
@@ -123,122 +191,6 @@ public abstract class BaseNCodec implements BinaryEncoder, BinaryDecoder {
*/
static final byte[] CHUNK_SEPARATOR = {'\r', '\n'};
- /**
- * @deprecated Use {@link #pad}. Will be removed in 2.0.
- */
- @Deprecated
- protected final byte PAD = PAD_DEFAULT; // instance variable just in case it needs to vary later
-
- /** Pad byte. Instance variable just in case it needs to vary later. */
- protected final byte pad;
-
- /** Number of bytes in each full block of unencoded data, e.g. 4 for Base64 and 5 for Base32 */
- private final int unencodedBlockSize;
-
- /** Number of bytes in each full block of encoded data, e.g. 3 for Base64 and 8 for Base32 */
- private final int encodedBlockSize;
-
- /**
- * Chunksize for encoding. Not used when decoding.
- * A value of zero or less implies no chunking of the encoded data.
- * Rounded down to the nearest multiple of encodedBlockSize.
- */
- protected final int lineLength;
-
- /**
- * Size of chunk separator. Not used unless {@link #lineLength} > 0.
- */
- private final int chunkSeparatorLength;
-
- /**
- * Defines the decoding behavior when the input bytes contain leftover trailing bits that
- * cannot be created by a valid encoding. These can be bits that are unused from the final
- * character or entire characters. The default mode is lenient decoding. Set this to
- * {@code true} to enable strict decoding.
- * <ul>
- * <li>Lenient: Any trailing bits are composed into 8-bit bytes where possible.
- * The remainder are discarded.
- * <li>Strict: The decoding will raise an {@link IllegalArgumentException} if trailing bits
- * are not part of a valid encoding. Any unused bits from the final character must
- * be zero. Impossible counts of entire final characters are not allowed.
- * </ul>
- * <p>
- * When strict decoding is enabled it is expected that the decoded bytes will be re-encoded
- * to a byte array that matches the original, i.e. no changes occur on the final
- * character. This requires that the input bytes use the same padding and alphabet
- * as the encoder.
- * </p>
- */
- private final CodecPolicy decodingPolicy;
-
- /**
- * Holds thread context so classes can be thread-safe.
- *
- * This class is not itself thread-safe; each thread must allocate its own copy.
- *
- * @since 1.7
- */
- static class Context {
-
- /**
- * Placeholder for the bytes we're dealing with for our based logic.
- * Bitwise operations store and extract the encoding or decoding from this variable.
- */
- int ibitWorkArea;
-
- /**
- * Placeholder for the bytes we're dealing with for our based logic.
- * Bitwise operations store and extract the encoding or decoding from this variable.
- */
- long lbitWorkArea;
-
- /**
- * Buffer for streaming.
- */
- byte[] buffer;
-
- /**
- * Position where next character should be written in the buffer.
- */
- int pos;
-
- /**
- * Position where next character should be read from the buffer.
- */
- int readPos;
-
- /**
- * Boolean flag to indicate the EOF has been reached. Once EOF has been reached, this object becomes useless,
- * and must be thrown away.
- */
- boolean eof;
-
- /**
- * Variable tracks how many characters have been written to the current line. Only used when encoding. We use
- * it to make sure each encoded line never goes beyond lineLength (if lineLength > 0).
- */
- int currentLinePos;
-
- /**
- * Writes to the buffer only occur after every 3/5 reads when encoding, and every 4/8 reads when decoding. This
- * variable helps track that.
- */
- int modulus;
-
- /**
- * Returns a String useful for debugging (especially within a debugger.)
- *
- * @return a String useful for debugging.
- */
- @SuppressWarnings("boxing") // OK to ignore boxing here
- @Override
- public String toString() {
- return String.format("%s[buffer=%s, currentLinePos=%s, eof=%s, ibitWorkArea=%s, lbitWorkArea=%s, " +
- "modulus=%s, pos=%s, readPos=%s]", this.getClass().getSimpleName(), Arrays.toString(buffer),
- currentLinePos, eof, ibitWorkArea, lbitWorkArea, modulus, pos, readPos);
- }
- }
-
/**
* Create a positive capacity at least as large the minimum required capacity.
* If the minimum capacity is negative then this throws an OutOfMemoryError as no array
@@ -311,6 +263,54 @@ public abstract class BaseNCodec implements BinaryEncoder, BinaryDecoder {
return b;
}
+ /**
+ * @deprecated Use {@link #pad}. Will be removed in 2.0.
+ */
+ @Deprecated
+ protected final byte PAD = PAD_DEFAULT; // instance variable just in case it needs to vary later
+
+ /** Pad byte. Instance variable just in case it needs to vary later. */
+ protected final byte pad;
+
+ /** Number of bytes in each full block of unencoded data, e.g. 4 for Base64 and 5 for Base32 */
+ private final int unencodedBlockSize;
+
+ /** Number of bytes in each full block of encoded data, e.g. 3 for Base64 and 8 for Base32 */
+ private final int encodedBlockSize;
+
+ /**
+ * Chunksize for encoding. Not used when decoding.
+ * A value of zero or less implies no chunking of the encoded data.
+ * Rounded down to the nearest multiple of encodedBlockSize.
+ */
+ protected final int lineLength;
+
+ /**
+ * Size of chunk separator. Not used unless {@link #lineLength} > 0.
+ */
+ private final int chunkSeparatorLength;
+
+ /**
+ * Defines the decoding behavior when the input bytes contain leftover trailing bits that
+ * cannot be created by a valid encoding. These can be bits that are unused from the final
+ * character or entire characters. The default mode is lenient decoding. Set this to
+ * {@code true} to enable strict decoding.
+ * <ul>
+ * <li>Lenient: Any trailing bits are composed into 8-bit bytes where possible.
+ * The remainder are discarded.
+ * <li>Strict: The decoding will raise an {@link IllegalArgumentException} if trailing bits
+ * are not part of a valid encoding. Any unused bits from the final character must
+ * be zero. Impossible counts of entire final characters are not allowed.
+ * </ul>
+ * <p>
+ * When strict decoding is enabled it is expected that the decoded bytes will be re-encoded
+ * to a byte array that matches the original, i.e. no changes occur on the final
+ * character. This requires that the input bytes use the same padding and alphabet
+ * as the encoder.
+ * </p>
+ */
+ private final CodecPolicy decodingPolicy;
+
/**
* Note {@code lineLength} is rounded down to the nearest multiple of the encoded block size.
* If {@code chunkSeparatorLength} is zero, then chunking is disabled.
diff --git a/src/main/java/org/apache/commons/codec/binary/Hex.java b/src/main/java/org/apache/commons/codec/binary/Hex.java
index 61e41ac0..1a859d6c 100644
--- a/src/main/java/org/apache/commons/codec/binary/Hex.java
+++ b/src/main/java/org/apache/commons/codec/binary/Hex.java
@@ -63,8 +63,6 @@ public class Hex implements BinaryEncoder, BinaryDecoder {
private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D',
'E', 'F' };
- private final Charset charset;
-
/**
* Converts an array of characters representing hexadecimal values into an array of bytes of those same values. The
* returned array will be half the length of the passed array, as it takes two characters to represent any given
@@ -373,6 +371,8 @@ public class Hex implements BinaryEncoder, BinaryDecoder {
return digit;
}
+ private final Charset charset;
+
/**
* Creates a new codec with the default charset name {@link #DEFAULT_CHARSET}
*/
diff --git a/src/main/java/org/apache/commons/codec/cli/Digest.java b/src/main/java/org/apache/commons/codec/cli/Digest.java
index dce99b6a..e111c353 100644
--- a/src/main/java/org/apache/commons/codec/cli/Digest.java
+++ b/src/main/java/org/apache/commons/codec/cli/Digest.java
@@ -35,10 +35,6 @@ import org.apache.commons.codec.digest.MessageDigestAlgorithms;
*/
public class Digest {
- private final String algorithm;
- private final String[] args;
- private final String[] inputs;
-
/**
* Runs the digest algorithm in {@code args[0]} on the file in {@code args[1]}. If there is no {@code args[1]}, use
* standard input.
@@ -56,6 +52,10 @@ public class Digest {
public static void main(final String[] args) throws IOException {
new Digest(args).run();
}
+ private final String algorithm;
+ private final String[] args;
+
+ private final String[] inputs;
private Digest(final String[] args) {
if (args == null) {
@@ -101,14 +101,6 @@ public class Digest {
}
}
- private void run(final String[] digestAlgorithms) throws IOException {
- for (final String messageDigestAlgorithm : digestAlgorithms) {
- if (DigestUtils.isAvailable(messageDigestAlgorithm)) {
- run(messageDigestAlgorithm + " ", messageDigestAlgorithm);
- }
- }
- }
-
private void run(final String prefix, final MessageDigest messageDigest) throws IOException {
if (inputs == null) {
println(prefix, DigestUtils.digest(messageDigest, System.in));
@@ -143,6 +135,14 @@ public class Digest {
run(prefix, DigestUtils.getDigest(messageDigestAlgorithm));
}
+ private void run(final String[] digestAlgorithms) throws IOException {
+ for (final String messageDigestAlgorithm : digestAlgorithms) {
+ if (DigestUtils.isAvailable(messageDigestAlgorithm)) {
+ run(messageDigestAlgorithm + " ", messageDigestAlgorithm);
+ }
+ }
+ }
+
@Override
public String toString() {
return String.format("%s %s", super.toString(), Arrays.toString(args));
diff --git a/src/main/java/org/apache/commons/codec/digest/Blake3.java b/src/main/java/org/apache/commons/codec/digest/Blake3.java
index e941c5bf..dcbc6ea8 100644
--- a/src/main/java/org/apache/commons/codec/digest/Blake3.java
+++ b/src/main/java/org/apache/commons/codec/digest/Blake3.java
@@ -75,27 +75,207 @@ import java.util.Objects;
*/
public final class Blake3 {
+ private static final class ChunkState {
+ private int[] chainingValue;
+ private final long chunkCounter;
+ private final int flags;
+
+ private final byte[] block = new byte[BLOCK_LEN];
+ private int blockLength;
+ private int blocksCompressed;
+
+ private ChunkState(final int[] key, final long chunkCounter, final int flags) {
+ chainingValue = key;
+ this.chunkCounter = chunkCounter;
+ this.flags = flags;
+ }
+
+ private int length() {
+ return BLOCK_LEN * blocksCompressed + blockLength;
+ }
+
+ private Output output() {
+ final int[] blockWords = unpackInts(block, BLOCK_INTS);
+ final int outputFlags = flags | startFlag() | CHUNK_END;
+ return new Output(chainingValue, blockWords, chunkCounter, blockLength, outputFlags);
+ }
+
+ private int startFlag() {
+ return blocksCompressed == 0 ? CHUNK_START : 0;
+ }
+
+ private void update(final byte[] input, int offset, int length) {
+ while (length > 0) {
+ if (blockLength == BLOCK_LEN) {
+ // If the block buffer is full, compress it and clear it. More
+ // input is coming, so this compression is not CHUNK_END.
+ final int[] blockWords = unpackInts(block, BLOCK_INTS);
+ chainingValue = Arrays.copyOf(
+ compress(chainingValue, blockWords, BLOCK_LEN, chunkCounter, flags | startFlag()),
+ CHAINING_VALUE_INTS);
+ blocksCompressed++;
+ blockLength = 0;
+ Arrays.fill(block, (byte) 0);
+ }
+
+ final int want = BLOCK_LEN - blockLength;
+ final int take = Math.min(want, length);
+ System.arraycopy(input, offset, block, blockLength, take);
+ blockLength += take;
+ offset += take;
+ length -= take;
+ }
+ }
+ }
+ private static final class EngineState {
+ private final int[] key;
+ private final int flags;
+ // Space for 54 subtree chaining values: 2^54 * CHUNK_LEN = 2^64
+ // No more than 54 entries can ever be added to this stack (after updating 2^64 bytes and not finalizing any)
+ // so we preallocate the stack here. This can be smaller in environments where the data limit is expected to
+ // be much lower.
+ private final int[][] cvStack = new int[54][];
+ private int stackLen;
+ private ChunkState state;
+
+ private EngineState(final int[] key, final int flags) {
+ this.key = key;
+ this.flags = flags;
+ state = new ChunkState(key, 0, flags);
+ }
+
+ // Section 5.1.2 of the BLAKE3 spec explains this algorithm in more detail.
+ private void addChunkCV(final int[] firstCV, final long totalChunks) {
+ // This chunk might complete some subtrees. For each completed subtree,
+ // its left child will be the current top entry in the CV stack, and
+ // its right child will be the current value of `newCV`. Pop each left
+ // child off the stack, merge it with `newCV`, and overwrite `newCV`
+ // with the result. After all these merges, push the final value of
+ // `newCV` onto the stack. The number of completed subtrees is given
+ // by the number of trailing 0-bits in the new total number of chunks.
+ int[] newCV = firstCV;
+ long chunkCounter = totalChunks;
+ while ((chunkCounter & 1) == 0) {
+ newCV = parentChainingValue(popCV(), newCV, key, flags);
+ chunkCounter >>= 1;
+ }
+ pushCV(newCV);
+ }
+
+ private void inputData(final byte[] in, int offset, int length) {
+ while (length > 0) {
+ // If the current chunk is complete, finalize it and reset the
+ // chunk state. More input is coming, so this chunk is not ROOT.
+ if (state.length() == CHUNK_LEN) {
+ final int[] chunkCV = state.output().chainingValue();
+ final long totalChunks = state.chunkCounter + 1;
+ addChunkCV(chunkCV, totalChunks);
+ state = new ChunkState(key, totalChunks, flags);
+ }
+
+ // Compress input bytes into the current chunk state.
+ final int want = CHUNK_LEN - state.length();
+ final int take = Math.min(want, length);
+ state.update(in, offset, take);
+ offset += take;
+ length -= take;
+ }
+ }
+
+ private void outputHash(final byte[] out, final int offset, final int length) {
+ // Starting with the Output from the current chunk, compute all the
+ // parent chaining values along the right edge of the tree, until we
+ // have the root Output.
+ Output output = state.output();
+ int parentNodesRemaining = stackLen;
+ while (parentNodesRemaining-- > 0) {
+ final int[] parentCV = cvStack[parentNodesRemaining];
+ output = parentOutput(parentCV, output.chainingValue(), key, flags);
+ }
+ output.rootOutputBytes(out, offset, length);
+ }
+
+ private int[] popCV() {
+ return cvStack[--stackLen];
+ }
+
+ private void pushCV(final int[] cv) {
+ cvStack[stackLen++] = cv;
+ }
+
+ private void reset() {
+ stackLen = 0;
+ Arrays.fill(cvStack, null);
+ state = new ChunkState(key, 0, flags);
+ }
+ }
+ /**
+ * Represents the state just prior to either producing an eight word chaining value or any number of output bytes
+ * when the ROOT flag is set.
+ */
+ private static final class Output {
+ private final int[] inputChainingValue;
+ private final int[] blockWords;
+ private final long counter;
+ private final int blockLength;
+ private final int flags;
+
+ private Output(
+ final int[] inputChainingValue, final int[] blockWords, final long counter, final int blockLength,
+ final int flags) {
+ this.inputChainingValue = inputChainingValue;
+ this.blockWords = blockWords;
+ this.counter = counter;
+ this.blockLength = blockLength;
+ this.flags = flags;
+ }
+
+ private int[] chainingValue() {
+ return Arrays
+ .copyOf(compress(inputChainingValue, blockWords, blockLength, counter, flags), CHAINING_VALUE_INTS);
+ }
+
+ private void rootOutputBytes(final byte[] out, int offset, int length) {
+ int outputBlockCounter = 0;
+ while (length > 0) {
+ int chunkLength = Math.min(OUT_LEN * 2, length);
+ length -= chunkLength;
+ final int[] words =
+ compress(inputChainingValue, blockWords, blockLength, outputBlockCounter++, flags | ROOT);
+ int wordCounter = 0;
+ while (chunkLength > 0) {
+ final int wordLength = Math.min(Integer.BYTES, chunkLength);
+ packInt(words[wordCounter++], out, offset, wordLength);
+ offset += wordLength;
+ chunkLength -= wordLength;
+ }
+ }
+ }
+ }
private static final int BLOCK_LEN = 64;
private static final int BLOCK_INTS = BLOCK_LEN / Integer.BYTES;
private static final int KEY_LEN = 32;
private static final int KEY_INTS = KEY_LEN / Integer.BYTES;
+
private static final int OUT_LEN = 32;
+
private static final int CHUNK_LEN = 1024;
private static final int CHAINING_VALUE_INTS = 8;
-
/**
* Standard hash key used for plain hashes; same initialization vector as Blake2s.
*/
private static final int[] IV =
{ 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 };
-
// domain flags
private static final int CHUNK_START = 1;
private static final int CHUNK_END = 1 << 1;
private static final int PARENT = 1 << 2;
private static final int ROOT = 1 << 3;
+
private static final int KEYED_HASH = 1 << 4;
+
private static final int DERIVE_KEY_CONTEXT = 1 << 5;
+
private static final int DERIVE_KEY_MATERIAL = 1 << 6;
/**
@@ -111,97 +291,69 @@ public final class Blake3 {
{ 11, 15, 5, 0, 1, 9, 8, 6, 14, 10, 2, 12, 3, 4, 7, 13 }
};
- private final EngineState engineState;
+ private static void checkBufferArgs(final byte[] buffer, final int offset, final int length) {
+ Objects.requireNonNull(buffer);
+ if (offset < 0) {
+ throw new IndexOutOfBoundsException("Offset must be non-negative");
+ }
+ if (length < 0) {
+ throw new IndexOutOfBoundsException("Length must be non-negative");
+ }
+ final int bufferLength = buffer.length;
+ if (offset > bufferLength - length) {
+ throw new IndexOutOfBoundsException(
+ "Offset " + offset + " and length " + length + " out of bounds with buffer length " + bufferLength);
+ }
+ }
- private Blake3(final int[] key, final int flags) {
- engineState = new EngineState(key, flags);
+ private static int[] compress(
+ final int[] chainingValue, final int[] blockWords, final int blockLength, final long counter,
+ final int flags) {
+ final int[] state = Arrays.copyOf(chainingValue, BLOCK_INTS);
+ System.arraycopy(IV, 0, state, 8, 4);
+ state[12] = (int) counter;
+ state[13] = (int) (counter >> Integer.SIZE);
+ state[14] = blockLength;
+ state[15] = flags;
+ for (int i = 0; i < 7; i++) {
+ final byte[] schedule = MSG_SCHEDULE[i];
+ round(state, blockWords, schedule);
+ }
+ for (int i = 0; i < state.length / 2; i++) {
+ state[i] ^= state[i + 8];
+ state[i + 8] ^= chainingValue[i];
+ }
+ return state;
}
/**
- * Resets this instance back to its initial state when it was first constructed.
- * @return this
+ * The mixing function, G, which mixes either a column or a diagonal.
*/
- public Blake3 reset() {
- engineState.reset();
- return this;
+ private static void g(
+ final int[] state, final int a, final int b, final int c, final int d, final int mx, final int my) {
+ state[a] += state[b] + mx;
+ state[d] = Integer.rotateRight(state[d] ^ state[a], 16);
+ state[c] += state[d];
+ state[b] = Integer.rotateRight(state[b] ^ state[c], 12);
+ state[a] += state[b] + my;
+ state[d] = Integer.rotateRight(state[d] ^ state[a], 8);
+ state[c] += state[d];
+ state[b] = Integer.rotateRight(state[b] ^ state[c], 7);
}
/**
- * Updates this hash state using the provided bytes.
+ * Calculates the Blake3 hash of the provided data.
*
- * @param in source array to update data from
- * @return this
- * @throws NullPointerException if in is null
+ * @param data source array to absorb data from
+ * @return 32-byte hash squeezed from the provided data
+ * @throws NullPointerException if data is null
*/
- public Blake3 update(final byte[] in) {
- return update(in, 0, in.length);
+ public static byte[] hash(final byte[] data) {
+ return Blake3.initHash().update(data).doFinalize(OUT_LEN);
}
/**
- * Updates this hash state using the provided bytes at an offset.
- *
- * @param in source array to update data from
- * @param offset where in the array to begin reading bytes
- * @param length number of bytes to update
- * @return this
- * @throws NullPointerException if in is null
- * @throws IndexOutOfBoundsException if offset or length are negative or if offset + length is greater than the
- * length of the provided array
- */
- public Blake3 update(final byte[] in, final int offset, final int length) {
- checkBufferArgs(in, offset, length);
- engineState.inputData(in, offset, length);
- return this;
- }
-
- /**
- * Finalizes hash output data that depends on the sequence of updated bytes preceding this invocation and any
- * previously finalized bytes. Note that this can finalize up to 2<sup>64</sup> bytes per instance.
- *
- * @param out destination array to finalize bytes into
- * @return this
- * @throws NullPointerException if out is null
- */
- public Blake3 doFinalize(final byte[] out) {
- return doFinalize(out, 0, out.length);
- }
-
- /**
- * Finalizes an arbitrary number of bytes into the provided output array that depends on the sequence of previously
- * updated and finalized bytes. Note that this can finalize up to 2<sup>64</sup> bytes per instance.
- *
- * @param out destination array to finalize bytes into
- * @param offset where in the array to begin writing bytes to
- * @param length number of bytes to finalize
- * @return this
- * @throws NullPointerException if out is null
- * @throws IndexOutOfBoundsException if offset or length are negative or if offset + length is greater than the
- * length of the provided array
- */
- public Blake3 doFinalize(final byte[] out, final int offset, final int length) {
- checkBufferArgs(out, offset, length);
- engineState.outputHash(out, offset, length);
- return this;
- }
-
- /**
- * Squeezes and returns an arbitrary number of bytes dependent on the sequence of previously absorbed and squeezed bytes.
- *
- * @param nrBytes number of bytes to finalize
- * @return requested number of finalized bytes
- * @throws IllegalArgumentException if nrBytes is negative
- */
- public byte[] doFinalize(final int nrBytes) {
- if (nrBytes < 0) {
- throw new IllegalArgumentException("Requested bytes must be non-negative");
- }
- final byte[] hash = new byte[nrBytes];
- doFinalize(hash);
- return hash;
- }
-
- /**
- * Constructs a fresh Blake3 hash function. The instance returned functions as an arbitrary length message digest.
+ * Constructs a fresh Blake3 hash function. The instance returned functions as an arbitrary length message digest.
*
* @return fresh Blake3 instance in hashed mode
*/
@@ -209,23 +361,6 @@ public final class Blake3 {
return new Blake3(IV, 0);
}
- /**
- * Constructs a fresh Blake3 keyed hash function. The instance returned functions as a pseudorandom function (PRF) or as a
- * message authentication code (MAC).
- *
- * @param key 32-byte secret key
- * @return fresh Blake3 instance in keyed mode using the provided key
- * @throws NullPointerException if key is null
- * @throws IllegalArgumentException if key is not 32 bytes
- */
- public static Blake3 initKeyedHash(final byte[] key) {
- Objects.requireNonNull(key);
- if (key.length != KEY_LEN) {
- throw new IllegalArgumentException("Blake3 keys must be 32 bytes");
- }
- return new Blake3(unpackInts(key, KEY_INTS), KEYED_HASH);
- }
-
/**
* Constructs a fresh Blake3 key derivation function using the provided key derivation context byte string.
* The instance returned functions as a key-derivation function which can further absorb additional context data
@@ -245,14 +380,20 @@ public final class Blake3 {
}
/**
- * Calculates the Blake3 hash of the provided data.
+ * Constructs a fresh Blake3 keyed hash function. The instance returned functions as a pseudorandom function (PRF) or as a
+ * message authentication code (MAC).
*
- * @param data source array to absorb data from
- * @return 32-byte hash squeezed from the provided data
- * @throws NullPointerException if data is null
+ * @param key 32-byte secret key
+ * @return fresh Blake3 instance in keyed mode using the provided key
+ * @throws NullPointerException if key is null
+ * @throws IllegalArgumentException if key is not 32 bytes
*/
- public static byte[] hash(final byte[] data) {
- return Blake3.initHash().update(data).doFinalize(OUT_LEN);
+ public static Blake3 initKeyedHash(final byte[] key) {
+ Objects.requireNonNull(key);
+ if (key.length != KEY_LEN) {
+ throw new IllegalArgumentException("Blake3 keys must be 32 bytes");
+ }
+ return new Blake3(unpackInts(key, KEY_INTS), KEYED_HASH);
}
/**
@@ -267,52 +408,22 @@ public final class Blake3 {
return Blake3.initKeyedHash(key).update(data).doFinalize(OUT_LEN);
}
- private static void checkBufferArgs(final byte[] buffer, final int offset, final int length) {
- Objects.requireNonNull(buffer);
- if (offset < 0) {
- throw new IndexOutOfBoundsException("Offset must be non-negative");
- }
- if (length < 0) {
- throw new IndexOutOfBoundsException("Length must be non-negative");
- }
- final int bufferLength = buffer.length;
- if (offset > bufferLength - length) {
- throw new IndexOutOfBoundsException(
- "Offset " + offset + " and length " + length + " out of bounds with buffer length " + bufferLength);
- }
- }
-
private static void packInt(final int value, final byte[] dst, final int off, final int len) {
for (int i = 0; i < len; i++) {
dst[off + i] = (byte) (value >>> i * Byte.SIZE);
}
}
- private static int unpackInt(final byte[] buf, final int off) {
- return buf[off] & 0xFF | (buf[off + 1] & 0xFF) << 8 | (buf[off + 2] & 0xFF) << 16 | (buf[off + 3] & 0xFF) << 24;
- }
-
- private static int[] unpackInts(final byte[] buf, final int nrInts) {
- final int[] values = new int[nrInts];
- for (int i = 0, off = 0; i < nrInts; i++, off += Integer.BYTES) {
- values[i] = unpackInt(buf, off);
- }
- return values;
+ private static int[] parentChainingValue(
+ final int[] leftChildCV, final int[] rightChildCV, final int[] key, final int flags) {
+ return parentOutput(leftChildCV, rightChildCV, key, flags).chainingValue();
}
- /**
- * The mixing function, G, which mixes either a column or a diagonal.
- */
- private static void g(
- final int[] state, final int a, final int b, final int c, final int d, final int mx, final int my) {
- state[a] += state[b] + mx;
- state[d] = Integer.rotateRight(state[d] ^ state[a], 16);
- state[c] += state[d];
- state[b] = Integer.rotateRight(state[b] ^ state[c], 12);
- state[a] += state[b] + my;
- state[d] = Integer.rotateRight(state[d] ^ state[a], 8);
- state[c] += state[d];
- state[b] = Integer.rotateRight(state[b] ^ state[c], 7);
+ private static Output parentOutput(
+ final int[] leftChildCV, final int[] rightChildCV, final int[] key, final int flags) {
+ final int[] blockWords = Arrays.copyOf(leftChildCV, BLOCK_INTS);
+ System.arraycopy(rightChildCV, 0, blockWords, 8, CHAINING_VALUE_INTS);
+ return new Output(key.clone(), blockWords, 0, BLOCK_LEN, flags | PARENT);
}
private static void round(final int[] state, final int[] msg, final byte[] schedule) {
@@ -329,216 +440,105 @@ public final class Blake3 {
g(state, 3, 4, 9, 14, msg[schedule[14]], msg[schedule[15]]);
}
- private static int[] compress(
- final int[] chainingValue, final int[] blockWords, final int blockLength, final long counter,
- final int flags) {
- final int[] state = Arrays.copyOf(chainingValue, BLOCK_INTS);
- System.arraycopy(IV, 0, state, 8, 4);
- state[12] = (int) counter;
- state[13] = (int) (counter >> Integer.SIZE);
- state[14] = blockLength;
- state[15] = flags;
- for (int i = 0; i < 7; i++) {
- final byte[] schedule = MSG_SCHEDULE[i];
- round(state, blockWords, schedule);
- }
- for (int i = 0; i < state.length / 2; i++) {
- state[i] ^= state[i + 8];
- state[i + 8] ^= chainingValue[i];
- }
- return state;
+ private static int unpackInt(final byte[] buf, final int off) {
+ return buf[off] & 0xFF | (buf[off + 1] & 0xFF) << 8 | (buf[off + 2] & 0xFF) << 16 | (buf[off + 3] & 0xFF) << 24;
}
- private static Output parentOutput(
- final int[] leftChildCV, final int[] rightChildCV, final int[] key, final int flags) {
- final int[] blockWords = Arrays.copyOf(leftChildCV, BLOCK_INTS);
- System.arraycopy(rightChildCV, 0, blockWords, 8, CHAINING_VALUE_INTS);
- return new Output(key.clone(), blockWords, 0, BLOCK_LEN, flags | PARENT);
+ private static int[] unpackInts(final byte[] buf, final int nrInts) {
+ final int[] values = new int[nrInts];
+ for (int i = 0, off = 0; i < nrInts; i++, off += Integer.BYTES) {
+ values[i] = unpackInt(buf, off);
+ }
+ return values;
}
- private static int[] parentChainingValue(
- final int[] leftChildCV, final int[] rightChildCV, final int[] key, final int flags) {
- return parentOutput(leftChildCV, rightChildCV, key, flags).chainingValue();
+ private final EngineState engineState;
+
+ private Blake3(final int[] key, final int flags) {
+ engineState = new EngineState(key, flags);
}
/**
- * Represents the state just prior to either producing an eight word chaining value or any number of output bytes
- * when the ROOT flag is set.
+ * Finalizes hash output data that depends on the sequence of updated bytes preceding this invocation and any
+ * previously finalized bytes. Note that this can finalize up to 2<sup>64</sup> bytes per instance.
+ *
+ * @param out destination array to finalize bytes into
+ * @return this
+ * @throws NullPointerException if out is null
*/
- private static final class Output {
- private final int[] inputChainingValue;
- private final int[] blockWords;
- private final long counter;
- private final int blockLength;
- private final int flags;
-
- private Output(
- final int[] inputChainingValue, final int[] blockWords, final long counter, final int blockLength,
- final int flags) {
- this.inputChainingValue = inputChainingValue;
- this.blockWords = blockWords;
- this.counter = counter;
- this.blockLength = blockLength;
- this.flags = flags;
- }
-
- private int[] chainingValue() {
- return Arrays
- .copyOf(compress(inputChainingValue, blockWords, blockLength, counter, flags), CHAINING_VALUE_INTS);
- }
-
- private void rootOutputBytes(final byte[] out, int offset, int length) {
- int outputBlockCounter = 0;
- while (length > 0) {
- int chunkLength = Math.min(OUT_LEN * 2, length);
- length -= chunkLength;
- final int[] words =
- compress(inputChainingValue, blockWords, blockLength, outputBlockCounter++, flags | ROOT);
- int wordCounter = 0;
- while (chunkLength > 0) {
- final int wordLength = Math.min(Integer.BYTES, chunkLength);
- packInt(words[wordCounter++], out, offset, wordLength);
- offset += wordLength;
- chunkLength -= wordLength;
- }
- }
- }
+ public Blake3 doFinalize(final byte[] out) {
+ return doFinalize(out, 0, out.length);
}
- private static final class ChunkState {
- private int[] chainingValue;
- private final long chunkCounter;
- private final int flags;
-
- private final byte[] block = new byte[BLOCK_LEN];
- private int blockLength;
- private int blocksCompressed;
-
- private ChunkState(final int[] key, final long chunkCounter, final int flags) {
- chainingValue = key;
- this.chunkCounter = chunkCounter;
- this.flags = flags;
- }
-
- private int length() {
- return BLOCK_LEN * blocksCompressed + blockLength;
- }
-
- private int startFlag() {
- return blocksCompressed == 0 ? CHUNK_START : 0;
- }
-
- private void update(final byte[] input, int offset, int length) {
- while (length > 0) {
- if (blockLength == BLOCK_LEN) {
- // If the block buffer is full, compress it and clear it. More
- // input is coming, so this compression is not CHUNK_END.
- final int[] blockWords = unpackInts(block, BLOCK_INTS);
- chainingValue = Arrays.copyOf(
- compress(chainingValue, blockWords, BLOCK_LEN, chunkCounter, flags | startFlag()),
- CHAINING_VALUE_INTS);
- blocksCompressed++;
- blockLength = 0;
- Arrays.fill(block, (byte) 0);
- }
-
- final int want = BLOCK_LEN - blockLength;
- final int take = Math.min(want, length);
- System.arraycopy(input, offset, block, blockLength, take);
- blockLength += take;
- offset += take;
- length -= take;
- }
- }
-
- private Output output() {
- final int[] blockWords = unpackInts(block, BLOCK_INTS);
- final int outputFlags = flags | startFlag() | CHUNK_END;
- return new Output(chainingValue, blockWords, chunkCounter, blockLength, outputFlags);
- }
+ /**
+ * Finalizes an arbitrary number of bytes into the provided output array that depends on the sequence of previously
+ * updated and finalized bytes. Note that this can finalize up to 2<sup>64</sup> bytes per instance.
+ *
+ * @param out destination array to finalize bytes into
+ * @param offset where in the array to begin writing bytes to
+ * @param length number of bytes to finalize
+ * @return this
+ * @throws NullPointerException if out is null
+ * @throws IndexOutOfBoundsException if offset or length are negative or if offset + length is greater than the
+ * length of the provided array
+ */
+ public Blake3 doFinalize(final byte[] out, final int offset, final int length) {
+ checkBufferArgs(out, offset, length);
+ engineState.outputHash(out, offset, length);
+ return this;
}
- private static final class EngineState {
- private final int[] key;
- private final int flags;
- // Space for 54 subtree chaining values: 2^54 * CHUNK_LEN = 2^64
- // No more than 54 entries can ever be added to this stack (after updating 2^64 bytes and not finalizing any)
- // so we preallocate the stack here. This can be smaller in environments where the data limit is expected to
- // be much lower.
- private final int[][] cvStack = new int[54][];
- private int stackLen;
- private ChunkState state;
-
- private EngineState(final int[] key, final int flags) {
- this.key = key;
- this.flags = flags;
- state = new ChunkState(key, 0, flags);
- }
-
- private void inputData(final byte[] in, int offset, int length) {
- while (length > 0) {
- // If the current chunk is complete, finalize it and reset the
- // chunk state. More input is coming, so this chunk is not ROOT.
- if (state.length() == CHUNK_LEN) {
- final int[] chunkCV = state.output().chainingValue();
- final long totalChunks = state.chunkCounter + 1;
- addChunkCV(chunkCV, totalChunks);
- state = new ChunkState(key, totalChunks, flags);
- }
-
- // Compress input bytes into the current chunk state.
- final int want = CHUNK_LEN - state.length();
- final int take = Math.min(want, length);
- state.update(in, offset, take);
- offset += take;
- length -= take;
- }
- }
-
- private void outputHash(final byte[] out, final int offset, final int length) {
- // Starting with the Output from the current chunk, compute all the
- // parent chaining values along the right edge of the tree, until we
- // have the root Output.
- Output output = state.output();
- int parentNodesRemaining = stackLen;
- while (parentNodesRemaining-- > 0) {
- final int[] parentCV = cvStack[parentNodesRemaining];
- output = parentOutput(parentCV, output.chainingValue(), key, flags);
- }
- output.rootOutputBytes(out, offset, length);
- }
-
- private void reset() {
- stackLen = 0;
- Arrays.fill(cvStack, null);
- state = new ChunkState(key, 0, flags);
+ /**
+ * Squeezes and returns an arbitrary number of bytes dependent on the sequence of previously absorbed and squeezed bytes.
+ *
+ * @param nrBytes number of bytes to finalize
+ * @return requested number of finalized bytes
+ * @throws IllegalArgumentException if nrBytes is negative
+ */
+ public byte[] doFinalize(final int nrBytes) {
+ if (nrBytes < 0) {
+ throw new IllegalArgumentException("Requested bytes must be non-negative");
}
+ final byte[] hash = new byte[nrBytes];
+ doFinalize(hash);
+ return hash;
+ }
- // Section 5.1.2 of the BLAKE3 spec explains this algorithm in more detail.
- private void addChunkCV(final int[] firstCV, final long totalChunks) {
- // This chunk might complete some subtrees. For each completed subtree,
- // its left child will be the current top entry in the CV stack, and
- // its right child will be the current value of `newCV`. Pop each left
- // child off the stack, merge it with `newCV`, and overwrite `newCV`
- // with the result. After all these merges, push the final value of
- // `newCV` onto the stack. The number of completed subtrees is given
- // by the number of trailing 0-bits in the new total number of chunks.
- int[] newCV = firstCV;
- long chunkCounter = totalChunks;
- while ((chunkCounter & 1) == 0) {
- newCV = parentChainingValue(popCV(), newCV, key, flags);
- chunkCounter >>= 1;
- }
- pushCV(newCV);
- }
+ /**
+ * Resets this instance back to its initial state when it was first constructed.
+ * @return this
+ */
+ public Blake3 reset() {
+ engineState.reset();
+ return this;
+ }
- private void pushCV(final int[] cv) {
- cvStack[stackLen++] = cv;
- }
+ /**
+ * Updates this hash state using the provided bytes.
+ *
+ * @param in source array to update data from
+ * @return this
+ * @throws NullPointerException if in is null
+ */
+ public Blake3 update(final byte[] in) {
+ return update(in, 0, in.length);
+ }
- private int[] popCV() {
- return cvStack[--stackLen];
- }
+ /**
+ * Updates this hash state using the provided bytes at an offset.
+ *
+ * @param in source array to update data from
+ * @param offset where in the array to begin reading bytes
+ * @param length number of bytes to update
+ * @return this
+ * @throws NullPointerException if in is null
+ * @throws IndexOutOfBoundsException if offset or length are negative or if offset + length is greater than the
+ * length of the provided array
+ */
+ public Blake3 update(final byte[] in, final int offset, final int length) {
+ checkBufferArgs(in, offset, length);
+ engineState.inputData(in, offset, length);
+ return this;
}
}
diff --git a/src/main/java/org/apache/commons/codec/digest/HmacUtils.java b/src/main/java/org/apache/commons/codec/digest/HmacUtils.java
index 21cb7e00..61481c16 100644
--- a/src/main/java/org/apache/commons/codec/digest/HmacUtils.java
+++ b/src/main/java/org/apache/commons/codec/digest/HmacUtils.java
@@ -59,40 +59,6 @@ public final class HmacUtils {
private static final int STREAM_BUFFER_LENGTH = 1024;
- private final Mac mac;
-
- /**
- * Returns whether this algorithm is available
- *
- * @param name the name to check
- * @return whether this algorithm is available
- * @since 1.11
- */
- public static boolean isAvailable(final String name) {
- try {
- Mac.getInstance(name);
- return true;
- } catch (final NoSuchAlgorithmException e) {
- return false;
- }
- }
-
- /**
- * Returns whether this algorithm is available
- *
- * @param name the name to check
- * @return whether this algorithm is available
- * @since 1.11
- */
- public static boolean isAvailable(final HmacAlgorithms name) {
- try {
- Mac.getInstance(name.getName());
- return true;
- } catch (final NoSuchAlgorithmException e) {
- return false;
- }
- }
-
/**
* Returns an initialized {@code Mac} for the HmacMD5 algorithm.
* <p>
@@ -357,8 +323,6 @@ public final class HmacUtils {
return new HmacUtils(HmacAlgorithms.HMAC_MD5, key).hmacHex(valueToDigest);
}
- // hmacSha1
-
/**
* Returns a HmacSHA1 Message Authentication Code (MAC) for the given key and value.
*
@@ -415,6 +379,8 @@ public final class HmacUtils {
return new HmacUtils(HmacAlgorithms.HMAC_SHA_1, key).hmac(valueToDigest);
}
+ // hmacSha1
+
/**
* Returns a HmacSHA1 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
*
@@ -583,8 +549,6 @@ public final class HmacUtils {
return new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key).hmacHex(valueToDigest);
}
- // hmacSha384
-
/**
* Returns a HmacSHA384 Message Authentication Code (MAC) for the given key and value.
*
@@ -641,6 +605,8 @@ public final class HmacUtils {
return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmac(valueToDigest);
}
+ // hmacSha384
+
/**
* Returns a HmacSHA384 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
*
@@ -697,8 +663,6 @@ public final class HmacUtils {
return new HmacUtils(HmacAlgorithms.HMAC_SHA_384, key).hmacHex(valueToDigest);
}
- // hmacSha512
-
/**
* Returns a HmacSHA512 Message Authentication Code (MAC) for the given key and value.
*
@@ -755,6 +719,8 @@ public final class HmacUtils {
return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmac(valueToDigest);
}
+ // hmacSha512
+
/**
* Returns a HmacSHA512 Message Authentication Code (MAC) as hexadecimal string (lowercase) for the given key and value.
*
@@ -811,6 +777,38 @@ public final class HmacUtils {
return new HmacUtils(HmacAlgorithms.HMAC_SHA_512, key).hmacHex(valueToDigest);
}
+ /**
+ * Returns whether this algorithm is available
+ *
+ * @param name the name to check
+ * @return whether this algorithm is available
+ * @since 1.11
+ */
+ public static boolean isAvailable(final HmacAlgorithms name) {
+ try {
+ Mac.getInstance(name.getName());
+ return true;
+ } catch (final NoSuchAlgorithmException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Returns whether this algorithm is available
+ *
+ * @param name the name to check
+ * @return whether this algorithm is available
+ * @since 1.11
+ */
+ public static boolean isAvailable(final String name) {
+ try {
+ Mac.getInstance(name);
+ return true;
+ } catch (final NoSuchAlgorithmException e) {
+ return false;
+ }
+ }
+
/**
* Resets and then updates the given {@link Mac} with the value.
*
@@ -874,6 +872,8 @@ public final class HmacUtils {
return mac;
}
+ private final Mac mac;
+
/**
* Preserves binary compatibility only.
* As for previous versions does not provide useful behavior
@@ -884,21 +884,17 @@ public final class HmacUtils {
this(null);
}
- private HmacUtils(final Mac mac) {
- this.mac = mac;
- }
-
/**
* Creates an instance using the provided algorithm type.
*
- * @param algorithm to use
- * @param key the key to use
+ * @param algorithm to use.
+ * @param key the key to use
* @throws IllegalArgumentException
* when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
* @since 1.11
*/
- public HmacUtils(final String algorithm, final byte[] key) {
- this(getInitializedMac(algorithm, key));
+ public HmacUtils(final HmacAlgorithms algorithm, final byte[] key) {
+ this(algorithm.getName(), key);
}
/**
@@ -910,8 +906,12 @@ public final class HmacUtils {
* when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
* @since 1.11
*/
- public HmacUtils(final String algorithm, final String key) {
- this(algorithm, StringUtils.getBytesUtf8(key));
+ public HmacUtils(final HmacAlgorithms algorithm, final String key) {
+ this(algorithm.getName(), StringUtils.getBytesUtf8(key));
+ }
+
+ private HmacUtils(final Mac mac) {
+ this.mac = mac;
}
/**
@@ -923,21 +923,21 @@ public final class HmacUtils {
* when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
* @since 1.11
*/
- public HmacUtils(final HmacAlgorithms algorithm, final String key) {
- this(algorithm.getName(), StringUtils.getBytesUtf8(key));
+ public HmacUtils(final String algorithm, final byte[] key) {
+ this(getInitializedMac(algorithm, key));
}
/**
* Creates an instance using the provided algorithm type.
*
- * @param algorithm to use.
- * @param key the key to use
+ * @param algorithm to use
+ * @param key the key to use
* @throws IllegalArgumentException
* when a {@link NoSuchAlgorithmException} is caught or key is null or key is invalid.
* @since 1.11
*/
- public HmacUtils(final HmacAlgorithms algorithm, final byte[] key) {
- this(algorithm.getName(), key);
+ public HmacUtils(final String algorithm, final String key) {
+ this(algorithm, StringUtils.getBytesUtf8(key));
}
/**
@@ -955,45 +955,72 @@ public final class HmacUtils {
* Returns the digest for the input data.
*
* @param valueToDigest the input to use
- * @return the digest as a hexadecimal String
+ * @return the digest as a byte[]
* @since 1.11
*/
- public String hmacHex(final byte[] valueToDigest) {
- return Hex.encodeHexString(hmac(valueToDigest));
+ public byte[] hmac(final ByteBuffer valueToDigest) {
+ mac.update(valueToDigest);
+ return mac.doFinal();
}
/**
- * Returns the digest for the input data.
+ * Returns the digest for the file.
*
- * @param valueToDigest the input to use, treated as UTF-8
- * @return the digest as a byte[]
+ * @param valueToDigest the file to use
+ * @return the digest
+ * @throws IOException
+ * If an I/O error occurs.
* @since 1.11
*/
- public byte[] hmac(final String valueToDigest) {
- return mac.doFinal(StringUtils.getBytesUtf8(valueToDigest));
+ public byte[] hmac(final File valueToDigest) throws IOException {
+ try (final BufferedInputStream stream = new BufferedInputStream(new FileInputStream(valueToDigest))) {
+ return hmac(stream);
+ }
+ }
+
+ /**
+ * Returns the digest for the stream.
+ *
+ * @param valueToDigest
+ * the data to use
+ * <p>
+ * The InputStream must not be null and will not be closed
+ * </p>
+ * @return the digest
+ * @throws IOException
+ * If an I/O error occurs.
+ * @since 1.11
+ */
+ public byte[] hmac(final InputStream valueToDigest) throws IOException {
+ final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
+ int read;
+
+ while ((read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH) ) > -1) {
+ mac.update(buffer, 0, read);
+ }
+ return mac.doFinal();
}
/**
* Returns the digest for the input data.
*
* @param valueToDigest the input to use, treated as UTF-8
- * @return the digest as a hexadecimal String
+ * @return the digest as a byte[]
* @since 1.11
*/
- public String hmacHex(final String valueToDigest) {
- return Hex.encodeHexString(hmac(valueToDigest));
+ public byte[] hmac(final String valueToDigest) {
+ return mac.doFinal(StringUtils.getBytesUtf8(valueToDigest));
}
/**
* Returns the digest for the input data.
*
* @param valueToDigest the input to use
- * @return the digest as a byte[]
+ * @return the digest as a hexadecimal String
* @since 1.11
*/
- public byte[] hmac(final ByteBuffer valueToDigest) {
- mac.update(valueToDigest);
- return mac.doFinal();
+ public String hmacHex(final byte[] valueToDigest) {
+ return Hex.encodeHexString(hmac(valueToDigest));
}
/**
@@ -1008,26 +1035,16 @@ public final class HmacUtils {
}
/**
- * Returns the digest for the stream.
+ * Returns the digest for the file.
*
- * @param valueToDigest
- * the data to use
- * <p>
- * The InputStream must not be null and will not be closed
- * </p>
- * @return the digest
+ * @param valueToDigest the file to use
+ * @return the digest as a hexadecimal String
* @throws IOException
* If an I/O error occurs.
* @since 1.11
*/
- public byte[] hmac(final InputStream valueToDigest) throws IOException {
- final byte[] buffer = new byte[STREAM_BUFFER_LENGTH];
- int read;
-
- while ((read = valueToDigest.read(buffer, 0, STREAM_BUFFER_LENGTH) ) > -1) {
- mac.update(buffer, 0, read);
- }
- return mac.doFinal();
+ public String hmacHex(final File valueToDigest) throws IOException {
+ return Hex.encodeHexString(hmac(valueToDigest));
}
/**
@@ -1048,30 +1065,13 @@ public final class HmacUtils {
}
/**
- * Returns the digest for the file.
- *
- * @param valueToDigest the file to use
- * @return the digest
- * @throws IOException
- * If an I/O error occurs.
- * @since 1.11
- */
- public byte[] hmac(final File valueToDigest) throws IOException {
- try (final BufferedInputStream stream = new BufferedInputStream(new FileInputStream(valueToDigest))) {
- return hmac(stream);
- }
- }
-
- /**
- * Returns the digest for the file.
+ * Returns the digest for the input data.
*
- * @param valueToDigest the file to use
+ * @param valueToDigest the input to use, treated as UTF-8
* @return the digest as a hexadecimal String
- * @throws IOException
- * If an I/O error occurs.
* @since 1.11
*/
- public String hmacHex(final File valueToDigest) throws IOException {
+ public String hmacHex(final String valueToDigest) {
return Hex.encodeHexString(hmac(valueToDigest));
}
diff --git a/src/main/java/org/apache/commons/codec/digest/MurmurHash2.java b/src/main/java/org/apache/commons/codec/digest/MurmurHash2.java
index 8174d6f8..04038f95 100644
--- a/src/main/java/org/apache/commons/codec/digest/MurmurHash2.java
+++ b/src/main/java/org/apache/commons/codec/digest/MurmurHash2.java
@@ -58,8 +58,54 @@ public final class MurmurHash2 {
private static final long M64 = 0xc6a4a7935bd1e995L;
private static final int R64 = 47;
- /** No instance methods. */
- private MurmurHash2() {
+ /**
+ * Gets the little-endian int from 4 bytes starting at the specified index.
+ *
+ * @param data The data
+ * @param index The index
+ * @return The little-endian int
+ */
+ private static int getLittleEndianInt(final byte[] data, final int index) {
+ return data[index ] & 0xff |
+ (data[index + 1] & 0xff) << 8 |
+ (data[index + 2] & 0xff) << 16 |
+ (data[index + 3] & 0xff) << 24;
+ }
+
+ /**
+ * Gets the little-endian long from 8 bytes starting at the specified index.
+ *
+ * @param data The data
+ * @param index The index
+ * @return The little-endian long
+ */
+ private static long getLittleEndianLong(final byte[] data, final int index) {
+ return (long) data[index ] & 0xff |
+ ((long) data[index + 1] & 0xff) << 8 |
+ ((long) data[index + 2] & 0xff) << 16 |
+ ((long) data[index + 3] & 0xff) << 24 |
+ ((long) data[index + 4] & 0xff) << 32 |
+ ((long) data[index + 5] & 0xff) << 40 |
+ ((long) data[index + 6] & 0xff) << 48 |
+ ((long) data[index + 7] & 0xff) << 56;
+ }
+
+ /**
+ * Generates a 32-bit hash from byte array with the given length and a default seed value.
+ * This is a helper method that will produce the same result as:
+ *
+ * <pre>
+ * int seed = 0x9747b28c;
+ * int hash = MurmurHash2.hash32(data, length, seed);
+ * </pre>
+ *
+ * @param data The input byte array
+ * @param length The length of the array
+ * @return The 32-bit hash
+ * @see #hash32(byte[], int, int)
+ */
+ public static int hash32(final byte[] data, final int length) {
+ return hash32(data, length, 0x9747b28c);
}
/**
@@ -109,24 +155,6 @@ public final class MurmurHash2 {
return h;
}
- /**
- * Generates a 32-bit hash from byte array with the given length and a default seed value.
- * This is a helper method that will produce the same result as:
- *
- * <pre>
- * int seed = 0x9747b28c;
- * int hash = MurmurHash2.hash32(data, length, seed);
- * </pre>
- *
- * @param data The input byte array
- * @param length The length of the array
- * @return The 32-bit hash
- * @see #hash32(byte[], int, int)
- */
- public static int hash32(final byte[] data, final int length) {
- return hash32(data, length, 0x9747b28c);
- }
-
/**
* Generates a 32-bit hash from a string with a default seed.
* <p>
@@ -171,6 +199,24 @@ public final class MurmurHash2 {
return hash32(text.substring(from, from + length));
}
+ /**
+ * Generates a 64-bit hash from byte array with given length and a default seed value.
+ * This is a helper method that will produce the same result as:
+ *
+ * <pre>
+ * int seed = 0xe17a1465;
+ * int hash = MurmurHash2.hash64(data, length, seed);
+ * </pre>
+ *
+ * @param data The input byte array
+ * @param length The length of the array
+ * @return The 64-bit hash
+ * @see #hash64(byte[], int, int)
+ */
+ public static long hash64(final byte[] data, final int length) {
+ return hash64(data, length, 0xe17a1465);
+ }
+
/**
* Generates a 64-bit hash from byte array of the given length and seed.
*
@@ -223,24 +269,6 @@ public final class MurmurHash2 {
return h;
}
- /**
- * Generates a 64-bit hash from byte array with given length and a default seed value.
- * This is a helper method that will produce the same result as:
- *
- * <pre>
- * int seed = 0xe17a1465;
- * int hash = MurmurHash2.hash64(data, length, seed);
- * </pre>
- *
- * @param data The input byte array
- * @param length The length of the array
- * @return The 64-bit hash
- * @see #hash64(byte[], int, int)
- */
- public static long hash64(final byte[] data, final int length) {
- return hash64(data, length, 0xe17a1465);
- }
-
/**
* Generates a 64-bit hash from a string with a default seed.
* <p>
@@ -287,35 +315,7 @@ public final class MurmurHash2 {
return hash64(text.substring(from, from + length));
}
- /**
- * Gets the little-endian int from 4 bytes starting at the specified index.
- *
- * @param data The data
- * @param index The index
- * @return The little-endian int
- */
- private static int getLittleEndianInt(final byte[] data, final int index) {
- return data[index ] & 0xff |
- (data[index + 1] & 0xff) << 8 |
- (data[index + 2] & 0xff) << 16 |
- (data[index + 3] & 0xff) << 24;
- }
-
- /**
- * Gets the little-endian long from 8 bytes starting at the specified index.
- *
- * @param data The data
- * @param index The index
- * @return The little-endian long
- */
- private static long getLittleEndianLong(final byte[] data, final int index) {
- return (long) data[index ] & 0xff |
- ((long) data[index + 1] & 0xff) << 8 |
- ((long) data[index + 2] & 0xff) << 16 |
- ((long) data[index + 3] & 0xff) << 24 |
- ((long) data[index + 4] & 0xff) << 32 |
- ((long) data[index + 5] & 0xff) << 40 |
- ((long) data[index + 6] & 0xff) << 48 |
- ((long) data[index + 7] & 0xff) << 56;
+ /** No instance methods. */
+ private MurmurHash2() {
}
}
diff --git a/src/main/java/org/apache/commons/codec/digest/MurmurHash3.java b/src/main/java/org/apache/commons/codec/digest/MurmurHash3.java
index 24ca412a..ff80c1f9 100644
--- a/src/main/java/org/apache/commons/codec/digest/MurmurHash3.java
+++ b/src/main/java/org/apache/commons/codec/digest/MurmurHash3.java
@@ -57,6 +57,238 @@ import org.apache.commons.codec.binary.StringUtils;
*/
public final class MurmurHash3 {
+ /**
+ * Generates 32-bit hash from input bytes. Bytes can be added incrementally and the new
+ * hash computed.
+ *
+ * <p>This is an implementation of the 32-bit hash function {@code MurmurHash3_x86_32}
+ * from Austin Appleby's original MurmurHash3 {@code c++} code in SMHasher.</p>
+ *
+ * <p>This implementation contains a sign-extension bug in the finalization step of
+ * any bytes left over from dividing the length by 4. This manifests if any of these
+ * bytes are negative.</p>
+ *
+ * @deprecated Use IncrementalHash32x86. This corrects the processing of trailing bytes.
+ */
+ @Deprecated
+ public static class IncrementalHash32 extends IncrementalHash32x86 {
+
+ /**
+ * {@inheritDoc}
+ *
+ * <p>This implementation contains a sign-extension bug in the finalization step of
+ * any bytes left over from dividing the length by 4. This manifests if any of these
+ * bytes are negative.<p>
+ *
+ * @deprecated Use IncrementalHash32x86. This corrects the processing of trailing bytes.
+ */
+ @Override
+ @Deprecated
+ int finalise(final int hash, final int unprocessedLength, final byte[] unprocessed, final int totalLen) {
+ int result = hash;
+ // ************
+ // Note: This fails to apply masking using 0xff to the 3 remaining bytes.
+ // ************
+ int k1 = 0;
+ switch (unprocessedLength) {
+ case 3:
+ k1 ^= unprocessed[2] << 16;
+ case 2:
+ k1 ^= unprocessed[1] << 8;
+ case 1:
+ k1 ^= unprocessed[0];
+
+ // mix functions
+ k1 *= C1_32;
+ k1 = Integer.rotateLeft(k1, R1_32);
+ k1 *= C2_32;
+ result ^= k1;
+ }
+
+ // finalization
+ result ^= totalLen;
+ return fmix32(result);
+ }
+ }
+
+ /**
+ * Generates 32-bit hash from input bytes. Bytes can be added incrementally and the new
+ * hash computed.
+ *
+ * <p>This is an implementation of the 32-bit hash function {@code MurmurHash3_x86_32}
+ * from Austin Appleby's original MurmurHash3 {@code c++} code in SMHasher.</p>
+ *
+ * @since 1.14
+ */
+ public static class IncrementalHash32x86 {
+
+ /** The size of byte blocks that are processed together. */
+ private static final int BLOCK_SIZE = 4;
+
+ /**
+ * Combines the bytes using an Or operation ({@code | } in a little-endian representation
+ * of a 32-bit integer; byte 1 will be the least significant byte, byte 4 the most
+ * significant.
+ *
+ * @param b1 The first byte
+ * @param b2 The second byte
+ * @param b3 The third byte
+ * @param b4 The fourth byte
+ * @return The 32-bit integer
+ */
+ private static int orBytes(final byte b1, final byte b2, final byte b3, final byte b4) {
+ return b1 & 0xff | (b2 & 0xff) << 8 | (b3 & 0xff) << 16 | (b4 & 0xff) << 24;
+ }
+
+ /** Up to 3 unprocessed bytes from input data. */
+ private final byte[] unprocessed = new byte[3];
+
+ /** The number of unprocessed bytes in the tail data. */
+ private int unprocessedLength;
+
+ /** The total number of input bytes added since the start. */
+ private int totalLen;
+
+ /**
+ * The current running hash.
+ * This must be finalised to generate the 32-bit hash value.
+ */
+ private int hash;
+
+ /**
+ * Adds the byte array to the current incremental hash.
+ *
+ * @param data The input byte array
+ * @param offset The offset of data
+ * @param length The length of array
+ */
+ public final void add(final byte[] data, final int offset, final int length) {
+ if (length <= 0) {
+ // Nothing to add
+ return;
+ }
+ totalLen += length;
+
+ // Process the bytes in blocks of 4.
+ // New bytes must be added to any current unprocessed bytes,
+ // then processed in blocks of 4 and the remaining bytes saved:
+ //
+ // |--|---------------------------|--|
+ // unprocessed
+ // main block
+ // remaining
+
+ // Check if the unprocessed bytes and new bytes can fill a block of 4.
+ // Make this overflow safe in the event that length is Integer.MAX_VALUE.
+ // Equivalent to: (unprocessedLength + length < BLOCK_SIZE)
+ if (unprocessedLength + length - BLOCK_SIZE < 0) {
+ // Not enough so add to the unprocessed bytes
+ System.arraycopy(data, offset, unprocessed, unprocessedLength, length);
+ unprocessedLength += length;
+ return;
+ }
+
+ // Combine unprocessed bytes with new bytes.
+ final int newOffset;
+ final int newLength;
+ if (unprocessedLength > 0) {
+ int k = -1;
+ switch (unprocessedLength) {
+ case 1:
+ k = orBytes(unprocessed[0], data[offset], data[offset + 1], data[offset + 2]);
+ break;
+ case 2:
+ k = orBytes(unprocessed[0], unprocessed[1], data[offset], data[offset + 1]);
+ break;
+ case 3:
+ k = orBytes(unprocessed[0], unprocessed[1], unprocessed[2], data[offset]);
+ break;
+ default:
+ throw new IllegalStateException("Unprocessed length should be 1, 2, or 3: " + unprocessedLength);
+ }
+ hash = mix32(k, hash);
+ // Update the offset and length
+ final int consumed = BLOCK_SIZE - unprocessedLength;
+ newOffset = offset + consumed;
+ newLength = length - consumed;
+ } else {
+ newOffset = offset;
+ newLength = length;
+ }
+
+ // Main processing of blocks of 4 bytes
+ final int nblocks = newLength >> 2;
+
+ for (int i = 0; i < nblocks; i++) {
+ final int index = newOffset + (i << 2);
+ final int k = getLittleEndianInt(data, index);
+ hash = mix32(k, hash);
+ }
+
+ // Save left-over unprocessed bytes
+ final int consumed = nblocks << 2;
+ unprocessedLength = newLength - consumed;
+ if (unprocessedLength != 0) {
+ System.arraycopy(data, newOffset + consumed, unprocessed, 0, unprocessedLength);
+ }
+ }
+
+ /**
+ * Generates the 32-bit hash value. Repeat calls to this method with no additional data
+ * will generate the same hash value.
+ *
+ * @return The 32-bit hash
+ */
+ public final int end() {
+ // Allow calling end() again after adding no data to return the same result.
+ return finalise(hash, unprocessedLength, unprocessed, totalLen);
+ }
+
+ /**
+ * Finalizes the running hash to the output 32-bit hash by processing remaining bytes
+ * and performing final mixing.
+ *
+ * @param hash The running hash
+ * @param unprocessedLength The number of unprocessed bytes in the tail data.
+ * @param unprocessed Up to 3 unprocessed bytes from input data.
+ * @param totalLen The total number of input bytes added since the start.
+ * @return The 32-bit hash
+ */
+ int finalise(final int hash, final int unprocessedLength, final byte[] unprocessed, final int totalLen) {
+ int result = hash;
+ int k1 = 0;
+ switch (unprocessedLength) {
+ case 3:
+ k1 ^= (unprocessed[2] & 0xff) << 16;
+ case 2:
+ k1 ^= (unprocessed[1] & 0xff) << 8;
+ case 1:
+ k1 ^= unprocessed[0] & 0xff;
+
+ // mix functions
+ k1 *= C1_32;
+ k1 = Integer.rotateLeft(k1, R1_32);
+ k1 *= C2_32;
+ result ^= k1;
+ }
+
+ // finalization
+ result ^= totalLen;
+ return fmix32(result);
+ }
+
+ /**
+ * Starts a new incremental hash.
+ *
+ * @param seed The initial seed value
+ */
+ public final void start(final int seed) {
+ // Reset
+ unprocessedLength = totalLen = 0;
+ this.hash = seed;
+ }
+ }
+
/**
* A random number to use for a hash code.
*
@@ -64,21 +296,19 @@ public final class MurmurHash3 {
*/
@Deprecated
public static final long NULL_HASHCODE = 2862933555777941757L;
-
/**
* A default seed to use for the murmur hash algorithm.
* Has the value {@code 104729}.
*/
public static final int DEFAULT_SEED = 104729;
-
// Constants for 32-bit variant
private static final int C1_32 = 0xcc9e2d51;
private static final int C2_32 = 0x1b873593;
private static final int R1_32 = 15;
private static final int R2_32 = 13;
+
private static final int M_32 = 5;
private static final int N_32 = 0xe6546b64;
-
// Constants for 128-bit variant
private static final long C1 = 0x87c37b91114253d5L;
private static final long C2 = 0x4cf5ad432745937fL;
@@ -86,290 +316,366 @@ public final class MurmurHash3 {
private static final int R2 = 27;
private static final int R3 = 33;
private static final int M = 5;
+
private static final int N1 = 0x52dce729;
+
private static final int N2 = 0x38495ab5;
- /** No instance methods. */
- private MurmurHash3() {
+ /**
+ * Performs the final avalanche mix step of the 32-bit hash function {@code MurmurHash3_x86_32}.
+ *
+ * @param hash The current hash
+ * @return The final hash
+ */
+ private static int fmix32(int hash) {
+ hash ^= hash >>> 16;
+ hash *= 0x85ebca6b;
+ hash ^= hash >>> 13;
+ hash *= 0xc2b2ae35;
+ hash ^= hash >>> 16;
+ return hash;
}
/**
- * Generates 32-bit hash from two longs with a default seed value.
- * This is a helper method that will produce the same result as:
+ * Performs the final avalanche mix step of the 64-bit hash function {@code MurmurHash3_x64_128}.
*
- * <pre>
- * int offset = 0;
- * int seed = 104729;
- * int hash = MurmurHash3.hash32x86(ByteBuffer.allocate(16)
- * .putLong(data1)
- * .putLong(data2)
- * .array(), offset, 16, seed);
- * </pre>
- *
- * @param data1 The first long to hash
- * @param data2 The second long to hash
- * @return The 32-bit hash
- * @see #hash32x86(byte[], int, int, int)
+ * @param hash The current hash
+ * @return The final hash
*/
- public static int hash32(final long data1, final long data2) {
- return hash32(data1, data2, DEFAULT_SEED);
+ private static long fmix64(long hash) {
+ hash ^= hash >>> 33;
+ hash *= 0xff51afd7ed558ccdL;
+ hash ^= hash >>> 33;
+ hash *= 0xc4ceb9fe1a85ec53L;
+ hash ^= hash >>> 33;
+ return hash;
}
/**
- * Generates 32-bit hash from two longs with the given seed.
- * This is a helper method that will produce the same result as:
- *
- * <pre>
- * int offset = 0;
- * int hash = MurmurHash3.hash32x86(ByteBuffer.allocate(16)
- * .putLong(data1)
- * .putLong(data2)
- * .array(), offset, 16, seed);
- * </pre>
+ * Gets the little-endian int from 4 bytes starting at the specified index.
*
- * @param data1 The first long to hash
- * @param data2 The second long to hash
- * @param seed The initial seed value
- * @return The 32-bit hash
- * @see #hash32x86(byte[], int, int, int)
+ * @param data The data
+ * @param index The index
+ * @return The little-endian int
*/
- public static int hash32(final long data1, final long data2, final int seed) {
- int hash = seed;
- final long r0 = Long.reverseBytes(data1);
- final long r1 = Long.reverseBytes(data2);
-
- hash = mix32((int) r0, hash);
- hash = mix32((int) (r0 >>> 32), hash);
- hash = mix32((int) r1, hash);
- hash = mix32((int) (r1 >>> 32), hash);
-
- hash ^= Long.BYTES * 2;
- return fmix32(hash);
+ private static int getLittleEndianInt(final byte[] data, final int index) {
+ return data[index ] & 0xff |
+ (data[index + 1] & 0xff) << 8 |
+ (data[index + 2] & 0xff) << 16 |
+ (data[index + 3] & 0xff) << 24;
}
/**
- * Generates 32-bit hash from a long with a default seed value.
- * This is a helper method that will produce the same result as:
- *
- * <pre>
- * int offset = 0;
- * int seed = 104729;
- * int hash = MurmurHash3.hash32x86(ByteBuffer.allocate(8)
- * .putLong(data)
- * .array(), offset, 8, seed);
- * </pre>
+ * Gets the little-endian long from 8 bytes starting at the specified index.
*
- * @param data The long to hash
- * @return The 32-bit hash
- * @see #hash32x86(byte[], int, int, int)
+ * @param data The data
+ * @param index The index
+ * @return The little-endian long
*/
- public static int hash32(final long data) {
- return hash32(data, DEFAULT_SEED);
+ private static long getLittleEndianLong(final byte[] data, final int index) {
+ return (long) data[index ] & 0xff |
+ ((long) data[index + 1] & 0xff) << 8 |
+ ((long) data[index + 2] & 0xff) << 16 |
+ ((long) data[index + 3] & 0xff) << 24 |
+ ((long) data[index + 4] & 0xff) << 32 |
+ ((long) data[index + 5] & 0xff) << 40 |
+ ((long) data[index + 6] & 0xff) << 48 |
+ ((long) data[index + 7] & 0xff) << 56;
}
/**
- * Generates 32-bit hash from a long with the given seed.
+ * Generates 128-bit hash from the byte array with a default seed.
* This is a helper method that will produce the same result as:
*
* <pre>
* int offset = 0;
- * int hash = MurmurHash3.hash32x86(ByteBuffer.allocate(8)
- * .putLong(data)
- * .array(), offset, 8, seed);
+ * int seed = 104729;
+ * int hash = MurmurHash3.hash128(data, offset, data.length, seed);
* </pre>
*
- * @param data The long to hash
- * @param seed The initial seed value
- * @return The 32-bit hash
- * @see #hash32x86(byte[], int, int, int)
+ * <p>Note: The sign extension bug in {@link #hash128(byte[], int, int, int)} does not effect
+ * this result as the default seed is positive.</p>
+ *
+ * @param data The input byte array
+ * @return The 128-bit hash (2 longs)
+ * @see #hash128(byte[], int, int, int)
*/
- public static int hash32(final long data, final int seed) {
- int hash = seed;
- final long r0 = Long.reverseBytes(data);
-
- hash = mix32((int) r0, hash);
- hash = mix32((int) (r0 >>> 32), hash);
-
- hash ^= Long.BYTES;
- return fmix32(hash);
+ public static long[] hash128(final byte[] data) {
+ return hash128(data, 0, data.length, DEFAULT_SEED);
}
/**
- * Generates 32-bit hash from the byte array with a default seed.
- * This is a helper method that will produce the same result as:
+ * Generates 128-bit hash from the byte array with the given offset, length and seed.
*
- * <pre>
- * int offset = 0;
- * int seed = 104729;
- * int hash = MurmurHash3.hash32(data, offset, data.length, seed);
- * </pre>
+ * <p>This is an implementation of the 128-bit hash function {@code MurmurHash3_x64_128}
+ * from Austin Appleby's original MurmurHash3 {@code c++} code in SMHasher.</p>
*
- * <p>This implementation contains a sign-extension bug in the finalization step of
- * any bytes left over from dividing the length by 4. This manifests if any of these
- * bytes are negative.</p>
+ * <p>This implementation contains a sign-extension bug in the seed initialization.
+ * This manifests if the seed is negative.</p>
*
* @param data The input byte array
- * @return The 32-bit hash
- * @see #hash32(byte[], int, int, int)
- * @deprecated Use {@link #hash32x86(byte[], int, int, int)}. This corrects the processing of trailing bytes.
+ * @param offset The first element of array
+ * @param length The length of array
+ * @param seed The initial seed value
+ * @return The 128-bit hash (2 longs)
+ * @deprecated Use {@link #hash128x64(byte[], int, int, int)}. This corrects the seed initialization.
*/
@Deprecated
- public static int hash32(final byte[] data) {
- return hash32(data, 0, data.length, DEFAULT_SEED);
+ public static long[] hash128(final byte[] data, final int offset, final int length, final int seed) {
+ // ************
+ // Note: This deliberately fails to apply masking using 0xffffffffL to the seed
+ // to maintain behavioral compatibility with the original version.
+ // The implicit conversion to a long will extend a negative sign
+ // bit through the upper 32-bits of the long seed. These should be zero.
+ // ************
+ return hash128x64Internal(data, offset, length, seed);
}
/**
- * Generates 32-bit hash from a string with a default seed.
+ * Generates 128-bit hash from a string with a default seed.
* <p>
* Before 1.14 the string was converted using default encoding.
* Since 1.14 the string is converted to bytes using UTF-8 encoding.
* </p>
+ * <p>
* This is a helper method that will produce the same result as:
+ * </p>
*
* <pre>
* int offset = 0;
* int seed = 104729;
* byte[] bytes = data.getBytes(StandardCharsets.UTF_8);
- * int hash = MurmurHash3.hash32(bytes, offset, bytes.length, seed);
+ * int hash = MurmurHash3.hash128(bytes, offset, bytes.length, seed);
* </pre>
*
- * <p>This implementation contains a sign-extension bug in the finalization step of
- * any bytes left over from dividing the length by 4. This manifests if any of these
- * bytes are negative.</p>
+ * <p>Note: The sign extension bug in {@link #hash128(byte[], int, int, int)} does not effect
+ * this result as the default seed is positive.</p>
*
- * @param data The input string
- * @return The 32-bit hash
- * @see #hash32(byte[], int, int, int)
- * @deprecated Use {@link #hash32x86(byte[], int, int, int)} with the bytes returned from
- * {@link String#getBytes(java.nio.charset.Charset)}. This corrects the processing of trailing bytes.
+ * @param data The input String
+ * @return The 128-bit hash (2 longs)
+ * @see #hash128(byte[], int, int, int)
+ * @deprecated Use {@link #hash128x64(byte[])} using the bytes returned from
+ * {@link String#getBytes(java.nio.charset.Charset)}.
*/
@Deprecated
- public static int hash32(final String data) {
+ public static long[] hash128(final String data) {
final byte[] bytes = StringUtils.getBytesUtf8(data);
- return hash32(bytes, 0, bytes.length, DEFAULT_SEED);
+ return hash128(bytes, 0, bytes.length, DEFAULT_SEED);
}
/**
- * Generates 32-bit hash from the byte array with the given length and a default seed.
+ * Generates 128-bit hash from the byte array with a seed of zero.
* This is a helper method that will produce the same result as:
*
* <pre>
* int offset = 0;
- * int seed = 104729;
- * int hash = MurmurHash3.hash32(data, offset, length, seed);
+ * int seed = 0;
+ * int hash = MurmurHash3.hash128x64(data, offset, data.length, seed);
* </pre>
*
- * <p>This implementation contains a sign-extension bug in the finalization step of
- * any bytes left over from dividing the length by 4. This manifests if any of these
- * bytes are negative.</p>
- *
* @param data The input byte array
- * @param length The length of array
- * @return The 32-bit hash
- * @see #hash32(byte[], int, int, int)
- * @deprecated Use {@link #hash32x86(byte[], int, int, int)}. This corrects the processing of trailing bytes.
+ * @return The 128-bit hash (2 longs)
+ * @see #hash128x64(byte[], int, int, int)
+ * @since 1.14
*/
- @Deprecated
- public static int hash32(final byte[] data, final int length) {
- return hash32(data, length, DEFAULT_SEED);
+ public static long[] hash128x64(final byte[] data) {
+ return hash128x64(data, 0, data.length, 0);
}
/**
- * Generates 32-bit hash from the byte array with the given length and seed. This is a
- * helper method that will produce the same result as:
- *
- * <pre>
- * int offset = 0;
- * int hash = MurmurHash3.hash32(data, offset, length, seed);
- * </pre>
+ * Generates 128-bit hash from the byte array with the given offset, length and seed.
*
- * <p>This implementation contains a sign-extension bug in the finalization step of
- * any bytes left over from dividing the length by 4. This manifests if any of these
- * bytes are negative.</p>
+ * <p>This is an implementation of the 128-bit hash function {@code MurmurHash3_x64_128}
+ * from Austin Appleby's original MurmurHash3 {@code c++} code in SMHasher.</p>
*
* @param data The input byte array
+ * @param offset The first element of array
* @param length The length of array
* @param seed The initial seed value
- * @return The 32-bit hash
- * @see #hash32(byte[], int, int, int)
- * @deprecated Use {@link #hash32x86(byte[], int, int, int)}. This corrects the processing of trailing bytes.
+ * @return The 128-bit hash (2 longs)
+ * @since 1.14
*/
- @Deprecated
- public static int hash32(final byte[] data, final int length, final int seed) {
- return hash32(data, 0, length, seed);
+ public static long[] hash128x64(final byte[] data, final int offset, final int length, final int seed) {
+ // Use an unsigned 32-bit integer as the seed
+ return hash128x64Internal(data, offset, length, seed & 0xffffffffL);
}
/**
- * Generates 32-bit hash from the byte array with the given offset, length and seed.
+ * Generates 128-bit hash from the byte array with the given offset, length and seed.
*
- * <p>This is an implementation of the 32-bit hash function {@code MurmurHash3_x86_32}
+ * <p>This is an implementation of the 128-bit hash function {@code MurmurHash3_x64_128}
* from Austin Appleby's original MurmurHash3 {@code c++} code in SMHasher.</p>
*
- * <p>This implementation contains a sign-extension bug in the finalization step of
- * any bytes left over from dividing the length by 4. This manifests if any of these
- * bytes are negative.</p>
- *
* @param data The input byte array
- * @param offset The offset of data
+ * @param offset The first element of array
* @param length The length of array
* @param seed The initial seed value
- * @return The 32-bit hash
- * @deprecated Use {@link #hash32x86(byte[], int, int, int)}. This corrects the processing of trailing bytes.
+ * @return The 128-bit hash (2 longs)
*/
- @Deprecated
- public static int hash32(final byte[] data, final int offset, final int length, final int seed) {
- int hash = seed;
- final int nblocks = length >> 2;
+ private static long[] hash128x64Internal(final byte[] data, final int offset, final int length, final long seed) {
+ long h1 = seed;
+ long h2 = seed;
+ final int nblocks = length >> 4;
// body
for (int i = 0; i < nblocks; i++) {
- final int index = offset + (i << 2);
- final int k = getLittleEndianInt(data, index);
- hash = mix32(k, hash);
- }
+ final int index = offset + (i << 4);
+ long k1 = getLittleEndianLong(data, index);
+ long k2 = getLittleEndianLong(data, index + 8);
- // tail
- // ************
- // Note: This fails to apply masking using 0xff to the 3 remaining bytes.
- // ************
- final int index = offset + (nblocks << 2);
- int k1 = 0;
- switch (offset + length - index) {
+ // mix functions for k1
+ k1 *= C1;
+ k1 = Long.rotateLeft(k1, R1);
+ k1 *= C2;
+ h1 ^= k1;
+ h1 = Long.rotateLeft(h1, R2);
+ h1 += h2;
+ h1 = h1 * M + N1;
+
+ // mix functions for k2
+ k2 *= C2;
+ k2 = Long.rotateLeft(k2, R3);
+ k2 *= C1;
+ h2 ^= k2;
+ h2 = Long.rotateLeft(h2, R1);
+ h2 += h1;
+ h2 = h2 * M + N2;
+ }
+
+ // tail
+ long k1 = 0;
+ long k2 = 0;
+ final int index = offset + (nblocks << 4);
+ switch (offset + length - index) {
+ case 15:
+ k2 ^= ((long) data[index + 14] & 0xff) << 48;
+ case 14:
+ k2 ^= ((long) data[index + 13] & 0xff) << 40;
+ case 13:
+ k2 ^= ((long) data[index + 12] & 0xff) << 32;
+ case 12:
+ k2 ^= ((long) data[index + 11] & 0xff) << 24;
+ case 11:
+ k2 ^= ((long) data[index + 10] & 0xff) << 16;
+ case 10:
+ k2 ^= ((long) data[index + 9] & 0xff) << 8;
+ case 9:
+ k2 ^= data[index + 8] & 0xff;
+ k2 *= C2;
+ k2 = Long.rotateLeft(k2, R3);
+ k2 *= C1;
+ h2 ^= k2;
+
+ case 8:
+ k1 ^= ((long) data[index + 7] & 0xff) << 56;
+ case 7:
+ k1 ^= ((long) data[index + 6] & 0xff) << 48;
+ case 6:
+ k1 ^= ((long) data[index + 5] & 0xff) << 40;
+ case 5:
+ k1 ^= ((long) data[index + 4] & 0xff) << 32;
+ case 4:
+ k1 ^= ((long) data[index + 3] & 0xff) << 24;
case 3:
- k1 ^= data[index + 2] << 16;
+ k1 ^= ((long) data[index + 2] & 0xff) << 16;
case 2:
- k1 ^= data[index + 1] << 8;
+ k1 ^= ((long) data[index + 1] & 0xff) << 8;
case 1:
- k1 ^= data[index];
-
- // mix functions
- k1 *= C1_32;
- k1 = Integer.rotateLeft(k1, R1_32);
- k1 *= C2_32;
- hash ^= k1;
+ k1 ^= data[index] & 0xff;
+ k1 *= C1;
+ k1 = Long.rotateLeft(k1, R1);
+ k1 *= C2;
+ h1 ^= k1;
}
- hash ^= length;
- return fmix32(hash);
+ // finalization
+ h1 ^= length;
+ h2 ^= length;
+
+ h1 += h2;
+ h2 += h1;
+
+ h1 = fmix64(h1);
+ h2 = fmix64(h2);
+
+ h1 += h2;
+ h2 += h1;
+
+ return new long[] { h1, h2 };
}
/**
- * Generates 32-bit hash from the byte array with a seed of zero.
+ * Generates 32-bit hash from the byte array with a default seed.
* This is a helper method that will produce the same result as:
*
* <pre>
* int offset = 0;
- * int seed = 0;
- * int hash = MurmurHash3.hash32x86(data, offset, data.length, seed);
+ * int seed = 104729;
+ * int hash = MurmurHash3.hash32(data, offset, data.length, seed);
* </pre>
*
+ * <p>This implementation contains a sign-extension bug in the finalization step of
+ * any bytes left over from dividing the length by 4. This manifests if any of these
+ * bytes are negative.</p>
+ *
* @param data The input byte array
* @return The 32-bit hash
- * @see #hash32x86(byte[], int, int, int)
- * @since 1.14
+ * @see #hash32(byte[], int, int, int)
+ * @deprecated Use {@link #hash32x86(byte[], int, int, int)}. This corrects the processing of trailing bytes.
*/
- public static int hash32x86(final byte[] data) {
- return hash32x86(data, 0, data.length, 0);
+ @Deprecated
+ public static int hash32(final byte[] data) {
+ return hash32(data, 0, data.length, DEFAULT_SEED);
+ }
+
+ /**
+ * Generates 32-bit hash from the byte array with the given length and a default seed.
+ * This is a helper method that will produce the same result as:
+ *
+ * <pre>
+ * int offset = 0;
+ * int seed = 104729;
+ * int hash = MurmurHash3.hash32(data, offset, length, seed);
+ * </pre>
+ *
+ * <p>This implementation contains a sign-extension bug in the finalization step of
+ * any bytes left over from dividing the length by 4. This manifests if any of these
+ * bytes are negative.</p>
+ *
+ * @param data The input byte array
+ * @param length The length of array
+ * @return The 32-bit hash
+ * @see #hash32(byte[], int, int, int)
+ * @deprecated Use {@link #hash32x86(byte[], int, int, int)}. This corrects the processing of trailing bytes.
+ */
+ @Deprecated
+ public static int hash32(final byte[] data, final int length) {
+ return hash32(data, length, DEFAULT_SEED);
+ }
+
+ /**
+ * Generates 32-bit hash from the byte array with the given length and seed. This is a
+ * helper method that will produce the same result as:
+ *
+ * <pre>
+ * int offset = 0;
+ * int hash = MurmurHash3.hash32(data, offset, length, seed);
+ * </pre>
+ *
+ * <p>This implementation contains a sign-extension bug in the finalization step of
+ * any bytes left over from dividing the length by 4. This manifests if any of these
+ * bytes are negative.</p>
+ *
+ * @param data The input byte array
+ * @param length The length of array
+ * @param seed The initial seed value
+ * @return The 32-bit hash
+ * @see #hash32(byte[], int, int, int)
+ * @deprecated Use {@link #hash32x86(byte[], int, int, int)}. This corrects the processing of trailing bytes.
+ */
+ @Deprecated
+ public static int hash32(final byte[] data, final int length, final int seed) {
+ return hash32(data, 0, length, seed);
}
/**
@@ -378,14 +684,19 @@ public final class MurmurHash3 {
* <p>This is an implementation of the 32-bit hash function {@code MurmurHash3_x86_32}
* from Austin Appleby's original MurmurHash3 {@code c++} code in SMHasher.</p>
*
+ * <p>This implementation contains a sign-extension bug in the finalization step of
+ * any bytes left over from dividing the length by 4. This manifests if any of these
+ * bytes are negative.</p>
+ *
* @param data The input byte array
* @param offset The offset of data
* @param length The length of array
* @param seed The initial seed value
* @return The 32-bit hash
- * @since 1.14
+ * @deprecated Use {@link #hash32x86(byte[], int, int, int)}. This corrects the processing of trailing bytes.
*/
- public static int hash32x86(final byte[] data, final int offset, final int length, final int seed) {
+ @Deprecated
+ public static int hash32(final byte[] data, final int offset, final int length, final int seed) {
int hash = seed;
final int nblocks = length >> 2;
@@ -397,15 +708,18 @@ public final class MurmurHash3 {
}
// tail
+ // ************
+ // Note: This fails to apply masking using 0xff to the 3 remaining bytes.
+ // ************
final int index = offset + (nblocks << 2);
int k1 = 0;
switch (offset + length - index) {
case 3:
- k1 ^= (data[index + 2] & 0xff) << 16;
+ k1 ^= data[index + 2] << 16;
case 2:
- k1 ^= (data[index + 1] & 0xff) << 8;
+ k1 ^= data[index + 1] << 8;
case 1:
- k1 ^= data[index] & 0xff;
+ k1 ^= data[index];
// mix functions
k1 *= C1_32;
@@ -419,137 +733,200 @@ public final class MurmurHash3 {
}
/**
- * Generates 64-bit hash from a long with a default seed.
- *
- * <p><strong>This is not part of the original MurmurHash3 {@code c++} implementation.</strong></p>
- *
- * <p>This is a Murmur3-like 64-bit variant.
- * The method does not produce the same result as either half of the hash bytes from
- * {@linkplain #hash128x64(byte[])} with the same byte data from the {@code long}.
- * This method will be removed in a future release.</p>
- *
- * <p>Note: The sign extension bug in {@link #hash64(byte[], int, int, int)} does not effect
- * this result as the default seed is positive.</p>
- *
- * <p>This is a helper method that will produce the same result as:</p>
+ * Generates 32-bit hash from a long with a default seed value.
+ * This is a helper method that will produce the same result as:
*
* <pre>
* int offset = 0;
* int seed = 104729;
- * long hash = MurmurHash3.hash64(ByteBuffer.allocate(8)
- * .putLong(data)
- * .array(), offset, 8, seed);
+ * int hash = MurmurHash3.hash32x86(ByteBuffer.allocate(8)
+ * .putLong(data)
+ * .array(), offset, 8, seed);
* </pre>
*
* @param data The long to hash
- * @return The 64-bit hash
- * @see #hash64(byte[], int, int, int)
- * @deprecated Not part of the MurmurHash3 implementation.
- * Use half of the hash bytes from {@link #hash128x64(byte[])} with the bytes from the {@code long}.
+ * @return The 32-bit hash
+ * @see #hash32x86(byte[], int, int, int)
*/
- @Deprecated
- public static long hash64(final long data) {
- long hash = DEFAULT_SEED;
- long k = Long.reverseBytes(data);
- // mix functions
- k *= C1;
- k = Long.rotateLeft(k, R1);
- k *= C2;
- hash ^= k;
- hash = Long.rotateLeft(hash, R2) * M + N1;
- // finalization
- hash ^= Long.BYTES;
- hash = fmix64(hash);
- return hash;
+ public static int hash32(final long data) {
+ return hash32(data, DEFAULT_SEED);
}
/**
- * Generates 64-bit hash from an int with a default seed.
- *
- * <p><strong>This is not part of the original MurmurHash3 {@code c++} implementation.</strong></p>
- *
- * <p>This is a Murmur3-like 64-bit variant.
- * The method does not produce the same result as either half of the hash bytes from
- * {@linkplain #hash128x64(byte[])} with the same byte data from the {@code int}.
- * This method will be removed in a future release.</p>
- *
- * <p>Note: The sign extension bug in {@link #hash64(byte[], int, int, int)} does not effect
- * this result as the default seed is positive.</p>
- *
- * <p>This is a helper method that will produce the same result as:</p>
+ * Generates 32-bit hash from a long with the given seed.
+ * This is a helper method that will produce the same result as:
*
* <pre>
* int offset = 0;
- * int seed = 104729;
- * long hash = MurmurHash3.hash64(ByteBuffer.allocate(4)
- * .putInt(data)
- * .array(), offset, 4, seed);
+ * int hash = MurmurHash3.hash32x86(ByteBuffer.allocate(8)
+ * .putLong(data)
+ * .array(), offset, 8, seed);
* </pre>
*
- * @param data The int to hash
- * @return The 64-bit hash
- * @see #hash64(byte[], int, int, int)
- * @deprecated Not part of the MurmurHash3 implementation.
- * Use half of the hash bytes from {@link #hash128x64(byte[])} with the bytes from the {@code int}.
+ * @param data The long to hash
+ * @param seed The initial seed value
+ * @return The 32-bit hash
+ * @see #hash32x86(byte[], int, int, int)
*/
- @Deprecated
- public static long hash64(final int data) {
- long k1 = Integer.reverseBytes(data) & -1L >>> 32;
- long hash = DEFAULT_SEED;
- k1 *= C1;
- k1 = Long.rotateLeft(k1, R1);
- k1 *= C2;
- hash ^= k1;
- // finalization
- hash ^= Integer.BYTES;
- hash = fmix64(hash);
- return hash;
+ public static int hash32(final long data, final int seed) {
+ int hash = seed;
+ final long r0 = Long.reverseBytes(data);
+
+ hash = mix32((int) r0, hash);
+ hash = mix32((int) (r0 >>> 32), hash);
+
+ hash ^= Long.BYTES;
+ return fmix32(hash);
}
/**
- * Generates 64-bit hash from a short with a default seed.
+ * Generates 32-bit hash from two longs with a default seed value.
+ * This is a helper method that will produce the same result as:
*
- * <p><strong>This is not part of the original MurmurHash3 {@code c++} implementation.</strong></p>
+ * <pre>
+ * int offset = 0;
+ * int seed = 104729;
+ * int hash = MurmurHash3.hash32x86(ByteBuffer.allocate(16)
+ * .putLong(data1)
+ * .putLong(data2)
+ * .array(), offset, 16, seed);
+ * </pre>
*
- * <p>This is a Murmur3-like 64-bit variant.
- * The method does not produce the same result as either half of the hash bytes from
- * {@linkplain #hash128x64(byte[])} with the same byte data from the {@code short}.
- * This method will be removed in a future release.</p>
+ * @param data1 The first long to hash
+ * @param data2 The second long to hash
+ * @return The 32-bit hash
+ * @see #hash32x86(byte[], int, int, int)
+ */
+ public static int hash32(final long data1, final long data2) {
+ return hash32(data1, data2, DEFAULT_SEED);
+ }
+
+ /**
+ * Generates 32-bit hash from two longs with the given seed.
+ * This is a helper method that will produce the same result as:
*
- * <p>Note: The sign extension bug in {@link #hash64(byte[], int, int, int)} does not effect
- * this result as the default seed is positive.</p>
+ * <pre>
+ * int offset = 0;
+ * int hash = MurmurHash3.hash32x86(ByteBuffer.allocate(16)
+ * .putLong(data1)
+ * .putLong(data2)
+ * .array(), offset, 16, seed);
+ * </pre>
*
- * <p>This is a helper method that will produce the same result as:</p>
+ * @param data1 The first long to hash
+ * @param data2 The second long to hash
+ * @param seed The initial seed value
+ * @return The 32-bit hash
+ * @see #hash32x86(byte[], int, int, int)
+ */
+ public static int hash32(final long data1, final long data2, final int seed) {
+ int hash = seed;
+ final long r0 = Long.reverseBytes(data1);
+ final long r1 = Long.reverseBytes(data2);
+
+ hash = mix32((int) r0, hash);
+ hash = mix32((int) (r0 >>> 32), hash);
+ hash = mix32((int) r1, hash);
+ hash = mix32((int) (r1 >>> 32), hash);
+
+ hash ^= Long.BYTES * 2;
+ return fmix32(hash);
+ }
+
+ /**
+ * Generates 32-bit hash from a string with a default seed.
+ * <p>
+ * Before 1.14 the string was converted using default encoding.
+ * Since 1.14 the string is converted to bytes using UTF-8 encoding.
+ * </p>
+ * This is a helper method that will produce the same result as:
*
* <pre>
* int offset = 0;
* int seed = 104729;
- * long hash = MurmurHash3.hash64(ByteBuffer.allocate(2)
- * .putShort(data)
- * .array(), offset, 2, seed);
+ * byte[] bytes = data.getBytes(StandardCharsets.UTF_8);
+ * int hash = MurmurHash3.hash32(bytes, offset, bytes.length, seed);
* </pre>
*
- * @param data The short to hash
- * @return The 64-bit hash
- * @see #hash64(byte[], int, int, int)
- * @deprecated Not part of the MurmurHash3 implementation.
- * Use half of the hash bytes from {@link #hash128x64(byte[])} with the bytes from the {@code short}.
+ * <p>This implementation contains a sign-extension bug in the finalization step of
+ * any bytes left over from dividing the length by 4. This manifests if any of these
+ * bytes are negative.</p>
+ *
+ * @param data The input string
+ * @return The 32-bit hash
+ * @see #hash32(byte[], int, int, int)
+ * @deprecated Use {@link #hash32x86(byte[], int, int, int)} with the bytes returned from
+ * {@link String#getBytes(java.nio.charset.Charset)}. This corrects the processing of trailing bytes.
*/
@Deprecated
- public static long hash64(final short data) {
- long hash = DEFAULT_SEED;
- long k1 = 0;
- k1 ^= ((long) data & 0xff) << 8;
- k1 ^= (long) ((data & 0xFF00) >> 8) & 0xff;
- k1 *= C1;
- k1 = Long.rotateLeft(k1, R1);
- k1 *= C2;
- hash ^= k1;
+ public static int hash32(final String data) {
+ final byte[] bytes = StringUtils.getBytesUtf8(data);
+ return hash32(bytes, 0, bytes.length, DEFAULT_SEED);
+ }
- // finalization
- hash ^= Short.BYTES;
- hash = fmix64(hash);
- return hash;
+ /**
+ * Generates 32-bit hash from the byte array with a seed of zero.
+ * This is a helper method that will produce the same result as:
+ *
+ * <pre>
+ * int offset = 0;
+ * int seed = 0;
+ * int hash = MurmurHash3.hash32x86(data, offset, data.length, seed);
+ * </pre>
+ *
+ * @param data The input byte array
+ * @return The 32-bit hash
+ * @see #hash32x86(byte[], int, int, int)
+ * @since 1.14
+ */
+ public static int hash32x86(final byte[] data) {
+ return hash32x86(data, 0, data.length, 0);
+ }
+
+ /**
+ * Generates 32-bit hash from the byte array with the given offset, length and seed.
+ *
+ * <p>This is an implementation of the 32-bit hash function {@code MurmurHash3_x86_32}
+ * from Austin Appleby's original MurmurHash3 {@code c++} code in SMHasher.</p>
+ *
+ * @param data The input byte array
+ * @param offset The offset of data
+ * @param length The length of array
+ * @param seed The initial seed value
+ * @return The 32-bit hash
+ * @since 1.14
+ */
+ public static int hash32x86(final byte[] data, final int offset, final int length, final int seed) {
+ int hash = seed;
+ final int nblocks = length >> 2;
+
+ // body
+ for (int i = 0; i < nblocks; i++) {
+ final int index = offset + (i << 2);
+ final int k = getLittleEndianInt(data, index);
+ hash = mix32(k, hash);
+ }
+
+ // tail
+ final int index = offset + (nblocks << 2);
+ int k1 = 0;
+ switch (offset + length - index) {
+ case 3:
+ k1 ^= (data[index + 2] & 0xff) << 16;
+ case 2:
+ k1 ^= (data[index + 1] & 0xff) << 8;
+ case 1:
+ k1 ^= data[index] & 0xff;
+
+ // mix functions
+ k1 *= C1_32;
+ k1 = Integer.rotateLeft(k1, R1_32);
+ k1 *= C2_32;
+ hash ^= k1;
+ }
+
+ hash ^= length;
+ return fmix32(hash);
}
/**
@@ -698,256 +1075,137 @@ public final class MurmurHash3 {
}
/**
- * Generates 128-bit hash from the byte array with a default seed.
- * This is a helper method that will produce the same result as:
+ * Generates 64-bit hash from an int with a default seed.
*
- * <pre>
- * int offset = 0;
- * int seed = 104729;
- * int hash = MurmurHash3.hash128(data, offset, data.length, seed);
- * </pre>
+ * <p><strong>This is not part of the original MurmurHash3 {@code c++} implementation.</strong></p>
*
- * <p>Note: The sign extension bug in {@link #hash128(byte[], int, int, int)} does not effect
+ * <p>This is a Murmur3-like 64-bit variant.
+ * The method does not produce the same result as either half of the hash bytes from
+ * {@linkplain #hash128x64(byte[])} with the same byte data from the {@code int}.
+ * This method will be removed in a future release.</p>
+ *
+ * <p>Note: The sign extension bug in {@link #hash64(byte[], int, int, int)} does not effect
* this result as the default seed is positive.</p>
*
- * @param data The input byte array
- * @return The 128-bit hash (2 longs)
- * @see #hash128(byte[], int, int, int)
- */
- public static long[] hash128(final byte[] data) {
- return hash128(data, 0, data.length, DEFAULT_SEED);
- }
-
- /**
- * Generates 128-bit hash from the byte array with a seed of zero.
- * This is a helper method that will produce the same result as:
+ * <p>This is a helper method that will produce the same result as:</p>
*
* <pre>
* int offset = 0;
- * int seed = 0;
- * int hash = MurmurHash3.hash128x64(data, offset, data.length, seed);
+ * int seed = 104729;
+ * long hash = MurmurHash3.hash64(ByteBuffer.allocate(4)
+ * .putInt(data)
+ * .array(), offset, 4, seed);
* </pre>
*
- * @param data The input byte array
- * @return The 128-bit hash (2 longs)
- * @see #hash128x64(byte[], int, int, int)
- * @since 1.14
+ * @param data The int to hash
+ * @return The 64-bit hash
+ * @see #hash64(byte[], int, int, int)
+ * @deprecated Not part of the MurmurHash3 implementation.
+ * Use half of the hash bytes from {@link #hash128x64(byte[])} with the bytes from the {@code int}.
*/
- public static long[] hash128x64(final byte[] data) {
- return hash128x64(data, 0, data.length, 0);
+ @Deprecated
+ public static long hash64(final int data) {
+ long k1 = Integer.reverseBytes(data) & -1L >>> 32;
+ long hash = DEFAULT_SEED;
+ k1 *= C1;
+ k1 = Long.rotateLeft(k1, R1);
+ k1 *= C2;
+ hash ^= k1;
+ // finalization
+ hash ^= Integer.BYTES;
+ hash = fmix64(hash);
+ return hash;
}
/**
- * Generates 128-bit hash from a string with a default seed.
- * <p>
- * Before 1.14 the string was converted using default encoding.
- * Since 1.14 the string is converted to bytes using UTF-8 encoding.
- * </p>
- * <p>
- * This is a helper method that will produce the same result as:
- * </p>
+ * Generates 64-bit hash from a long with a default seed.
*
- * <pre>
- * int offset = 0;
- * int seed = 104729;
- * byte[] bytes = data.getBytes(StandardCharsets.UTF_8);
- * int hash = MurmurHash3.hash128(bytes, offset, bytes.length, seed);
- * </pre>
+ * <p><strong>This is not part of the original MurmurHash3 {@code c++} implementation.</strong></p>
*
- * <p>Note: The sign extension bug in {@link #hash128(byte[], int, int, int)} does not effect
+ * <p>This is a Murmur3-like 64-bit variant.
+ * The method does not produce the same result as either half of the hash bytes from
+ * {@linkplain #hash128x64(byte[])} with the same byte data from the {@code long}.
+ * This method will be removed in a future release.</p>
+ *
+ * <p>Note: The sign extension bug in {@link #hash64(byte[], int, int, int)} does not effect
* this result as the default seed is positive.</p>
*
- * @param data The input String
- * @return The 128-bit hash (2 longs)
- * @see #hash128(byte[], int, int, int)
- * @deprecated Use {@link #hash128x64(byte[])} using the bytes returned from
- * {@link String#getBytes(java.nio.charset.Charset)}.
- */
- @Deprecated
- public static long[] hash128(final String data) {
- final byte[] bytes = StringUtils.getBytesUtf8(data);
- return hash128(bytes, 0, bytes.length, DEFAULT_SEED);
- }
-
- /**
- * Generates 128-bit hash from the byte array with the given offset, length and seed.
- *
- * <p>This is an implementation of the 128-bit hash function {@code MurmurHash3_x64_128}
- * from Austin Appleby's original MurmurHash3 {@code c++} code in SMHasher.</p>
+ * <p>This is a helper method that will produce the same result as:</p>
*
- * <p>This implementation contains a sign-extension bug in the seed initialization.
- * This manifests if the seed is negative.</p>
+ * <pre>
+ * int offset = 0;
+ * int seed = 104729;
+ * long hash = MurmurHash3.hash64(ByteBuffer.allocate(8)
+ * .putLong(data)
+ * .array(), offset, 8, seed);
+ * </pre>
*
- * @param data The input byte array
- * @param offset The first element of array
- * @param length The length of array
- * @param seed The initial seed value
- * @return The 128-bit hash (2 longs)
- * @deprecated Use {@link #hash128x64(byte[], int, int, int)}. This corrects the seed initialization.
+ * @param data The long to hash
+ * @return The 64-bit hash
+ * @see #hash64(byte[], int, int, int)
+ * @deprecated Not part of the MurmurHash3 implementation.
+ * Use half of the hash bytes from {@link #hash128x64(byte[])} with the bytes from the {@code long}.
*/
@Deprecated
- public static long[] hash128(final byte[] data, final int offset, final int length, final int seed) {
- // ************
- // Note: This deliberately fails to apply masking using 0xffffffffL to the seed
- // to maintain behavioral compatibility with the original version.
- // The implicit conversion to a long will extend a negative sign
- // bit through the upper 32-bits of the long seed. These should be zero.
- // ************
- return hash128x64Internal(data, offset, length, seed);
+ public static long hash64(final long data) {
+ long hash = DEFAULT_SEED;
+ long k = Long.reverseBytes(data);
+ // mix functions
+ k *= C1;
+ k = Long.rotateLeft(k, R1);
+ k *= C2;
+ hash ^= k;
+ hash = Long.rotateLeft(hash, R2) * M + N1;
+ // finalization
+ hash ^= Long.BYTES;
+ hash = fmix64(hash);
+ return hash;
}
/**
- * Generates 128-bit hash from the byte array with the given offset, length and seed.
+ * Generates 64-bit hash from a short with a default seed.
*
- * <p>This is an implementation of the 128-bit hash function {@code MurmurHash3_x64_128}
- * from Austin Appleby's original MurmurHash3 {@code c++} code in SMHasher.</p>
+ * <p><strong>This is not part of the original MurmurHash3 {@code c++} implementation.</strong></p>
*
- * @param data The input byte array
- * @param offset The first element of array
- * @param length The length of array
- * @param seed The initial seed value
- * @return The 128-bit hash (2 longs)
- * @since 1.14
- */
- public static long[] hash128x64(final byte[] data, final int offset, final int length, final int seed) {
- // Use an unsigned 32-bit integer as the seed
- return hash128x64Internal(data, offset, length, seed & 0xffffffffL);
- }
-
- /**
- * Generates 128-bit hash from the byte array with the given offset, length and seed.
+ * <p>This is a Murmur3-like 64-bit variant.
+ * The method does not produce the same result as either half of the hash bytes from
+ * {@linkplain #hash128x64(byte[])} with the same byte data from the {@code short}.
+ * This method will be removed in a future release.</p>
*
- * <p>This is an implementation of the 128-bit hash function {@code MurmurHash3_x64_128}
- * from Austin Appleby's original MurmurHash3 {@code c++} code in SMHasher.</p>
+ * <p>Note: The sign extension bug in {@link #hash64(byte[], int, int, int)} does not effect
+ * this result as the default seed is positive.</p>
*
- * @param data The input byte array
- * @param offset The first element of array
- * @param length The length of array
- * @param seed The initial seed value
- * @return The 128-bit hash (2 longs)
+ * <p>This is a helper method that will produce the same result as:</p>
+ *
+ * <pre>
+ * int offset = 0;
+ * int seed = 104729;
+ * long hash = MurmurHash3.hash64(ByteBuffer.allocate(2)
+ * .putShort(data)
+ * .array(), offset, 2, seed);
+ * </pre>
+ *
+ * @param data The short to hash
+ * @return The 64-bit hash
+ * @see #hash64(byte[], int, int, int)
+ * @deprecated Not part of the MurmurHash3 implementation.
+ * Use half of the hash bytes from {@link #hash128x64(byte[])} with the bytes from the {@code short}.
*/
- private static long[] hash128x64Internal(final byte[] data, final int offset, final int length, final long seed) {
- long h1 = seed;
- long h2 = seed;
- final int nblocks = length >> 4;
-
- // body
- for (int i = 0; i < nblocks; i++) {
- final int index = offset + (i << 4);
- long k1 = getLittleEndianLong(data, index);
- long k2 = getLittleEndianLong(data, index + 8);
-
- // mix functions for k1
- k1 *= C1;
- k1 = Long.rotateLeft(k1, R1);
- k1 *= C2;
- h1 ^= k1;
- h1 = Long.rotateLeft(h1, R2);
- h1 += h2;
- h1 = h1 * M + N1;
-
- // mix functions for k2
- k2 *= C2;
- k2 = Long.rotateLeft(k2, R3);
- k2 *= C1;
- h2 ^= k2;
- h2 = Long.rotateLeft(h2, R1);
- h2 += h1;
- h2 = h2 * M + N2;
- }
-
- // tail
+ @Deprecated
+ public static long hash64(final short data) {
+ long hash = DEFAULT_SEED;
long k1 = 0;
- long k2 = 0;
- final int index = offset + (nblocks << 4);
- switch (offset + length - index) {
- case 15:
- k2 ^= ((long) data[index + 14] & 0xff) << 48;
- case 14:
- k2 ^= ((long) data[index + 13] & 0xff) << 40;
- case 13:
- k2 ^= ((long) data[index + 12] & 0xff) << 32;
- case 12:
- k2 ^= ((long) data[index + 11] & 0xff) << 24;
- case 11:
- k2 ^= ((long) data[index + 10] & 0xff) << 16;
- case 10:
- k2 ^= ((long) data[index + 9] & 0xff) << 8;
- case 9:
- k2 ^= data[index + 8] & 0xff;
- k2 *= C2;
- k2 = Long.rotateLeft(k2, R3);
- k2 *= C1;
- h2 ^= k2;
-
- case 8:
- k1 ^= ((long) data[index + 7] & 0xff) << 56;
- case 7:
- k1 ^= ((long) data[index + 6] & 0xff) << 48;
- case 6:
- k1 ^= ((long) data[index + 5] & 0xff) << 40;
- case 5:
- k1 ^= ((long) data[index + 4] & 0xff) << 32;
- case 4:
- k1 ^= ((long) data[index + 3] & 0xff) << 24;
- case 3:
- k1 ^= ((long) data[index + 2] & 0xff) << 16;
- case 2:
- k1 ^= ((long) data[index + 1] & 0xff) << 8;
- case 1:
- k1 ^= data[index] & 0xff;
- k1 *= C1;
- k1 = Long.rotateLeft(k1, R1);
- k1 *= C2;
- h1 ^= k1;
- }
+ k1 ^= ((long) data & 0xff) << 8;
+ k1 ^= (long) ((data & 0xFF00) >> 8) & 0xff;
+ k1 *= C1;
+ k1 = Long.rotateLeft(k1, R1);
+ k1 *= C2;
+ hash ^= k1;
// finalization
- h1 ^= length;
- h2 ^= length;
-
- h1 += h2;
- h2 += h1;
-
- h1 = fmix64(h1);
- h2 = fmix64(h2);
-
- h1 += h2;
- h2 += h1;
-
- return new long[] { h1, h2 };
- }
-
- /**
- * Gets the little-endian long from 8 bytes starting at the specified index.
- *
- * @param data The data
- * @param index The index
- * @return The little-endian long
- */
- private static long getLittleEndianLong(final byte[] data, final int index) {
- return (long) data[index ] & 0xff |
- ((long) data[index + 1] & 0xff) << 8 |
- ((long) data[index + 2] & 0xff) << 16 |
- ((long) data[index + 3] & 0xff) << 24 |
- ((long) data[index + 4] & 0xff) << 32 |
- ((long) data[index + 5] & 0xff) << 40 |
- ((long) data[index + 6] & 0xff) << 48 |
- ((long) data[index + 7] & 0xff) << 56;
- }
-
- /**
- * Gets the little-endian int from 4 bytes starting at the specified index.
- *
- * @param data The data
- * @param index The index
- * @return The little-endian int
- */
- private static int getLittleEndianInt(final byte[] data, final int index) {
- return data[index ] & 0xff |
- (data[index + 1] & 0xff) << 8 |
- (data[index + 2] & 0xff) << 16 |
- (data[index + 3] & 0xff) << 24;
+ hash ^= Short.BYTES;
+ hash = fmix64(hash);
+ return hash;
}
/**
@@ -965,265 +1223,7 @@ public final class MurmurHash3 {
return Integer.rotateLeft(hash, R2_32) * M_32 + N_32;
}
- /**
- * Performs the final avalanche mix step of the 32-bit hash function {@code MurmurHash3_x86_32}.
- *
- * @param hash The current hash
- * @return The final hash
- */
- private static int fmix32(int hash) {
- hash ^= hash >>> 16;
- hash *= 0x85ebca6b;
- hash ^= hash >>> 13;
- hash *= 0xc2b2ae35;
- hash ^= hash >>> 16;
- return hash;
- }
-
- /**
- * Performs the final avalanche mix step of the 64-bit hash function {@code MurmurHash3_x64_128}.
- *
- * @param hash The current hash
- * @return The final hash
- */
- private static long fmix64(long hash) {
- hash ^= hash >>> 33;
- hash *= 0xff51afd7ed558ccdL;
- hash ^= hash >>> 33;
- hash *= 0xc4ceb9fe1a85ec53L;
- hash ^= hash >>> 33;
- return hash;
- }
-
- /**
- * Generates 32-bit hash from input bytes. Bytes can be added incrementally and the new
- * hash computed.
- *
- * <p>This is an implementation of the 32-bit hash function {@code MurmurHash3_x86_32}
- * from Austin Appleby's original MurmurHash3 {@code c++} code in SMHasher.</p>
- *
- * @since 1.14
- */
- public static class IncrementalHash32x86 {
-
- /** The size of byte blocks that are processed together. */
- private static final int BLOCK_SIZE = 4;
-
- /** Up to 3 unprocessed bytes from input data. */
- private final byte[] unprocessed = new byte[3];
-
- /** The number of unprocessed bytes in the tail data. */
- private int unprocessedLength;
-
- /** The total number of input bytes added since the start. */
- private int totalLen;
-
- /**
- * The current running hash.
- * This must be finalised to generate the 32-bit hash value.
- */
- private int hash;
-
- /**
- * Starts a new incremental hash.
- *
- * @param seed The initial seed value
- */
- public final void start(final int seed) {
- // Reset
- unprocessedLength = totalLen = 0;
- this.hash = seed;
- }
-
- /**
- * Adds the byte array to the current incremental hash.
- *
- * @param data The input byte array
- * @param offset The offset of data
- * @param length The length of array
- */
- public final void add(final byte[] data, final int offset, final int length) {
- if (length <= 0) {
- // Nothing to add
- return;
- }
- totalLen += length;
-
- // Process the bytes in blocks of 4.
- // New bytes must be added to any current unprocessed bytes,
- // then processed in blocks of 4 and the remaining bytes saved:
- //
- // |--|---------------------------|--|
- // unprocessed
- // main block
- // remaining
-
- // Check if the unprocessed bytes and new bytes can fill a block of 4.
- // Make this overflow safe in the event that length is Integer.MAX_VALUE.
- // Equivalent to: (unprocessedLength + length < BLOCK_SIZE)
- if (unprocessedLength + length - BLOCK_SIZE < 0) {
- // Not enough so add to the unprocessed bytes
- System.arraycopy(data, offset, unprocessed, unprocessedLength, length);
- unprocessedLength += length;
- return;
- }
-
- // Combine unprocessed bytes with new bytes.
- final int newOffset;
- final int newLength;
- if (unprocessedLength > 0) {
- int k = -1;
- switch (unprocessedLength) {
- case 1:
- k = orBytes(unprocessed[0], data[offset], data[offset + 1], data[offset + 2]);
- break;
- case 2:
- k = orBytes(unprocessed[0], unprocessed[1], data[offset], data[offset + 1]);
- break;
- case 3:
- k = orBytes(unprocessed[0], unprocessed[1], unprocessed[2], data[offset]);
- break;
- default:
- throw new IllegalStateException("Unprocessed length should be 1, 2, or 3: " + unprocessedLength);
- }
- hash = mix32(k, hash);
- // Update the offset and length
- final int consumed = BLOCK_SIZE - unprocessedLength;
- newOffset = offset + consumed;
- newLength = length - consumed;
- } else {
- newOffset = offset;
- newLength = length;
- }
-
- // Main processing of blocks of 4 bytes
- final int nblocks = newLength >> 2;
-
- for (int i = 0; i < nblocks; i++) {
- final int index = newOffset + (i << 2);
- final int k = getLittleEndianInt(data, index);
- hash = mix32(k, hash);
- }
-
- // Save left-over unprocessed bytes
- final int consumed = nblocks << 2;
- unprocessedLength = newLength - consumed;
- if (unprocessedLength != 0) {
- System.arraycopy(data, newOffset + consumed, unprocessed, 0, unprocessedLength);
- }
- }
-
- /**
- * Generates the 32-bit hash value. Repeat calls to this method with no additional data
- * will generate the same hash value.
- *
- * @return The 32-bit hash
- */
- public final int end() {
- // Allow calling end() again after adding no data to return the same result.
- return finalise(hash, unprocessedLength, unprocessed, totalLen);
- }
-
- /**
- * Finalizes the running hash to the output 32-bit hash by processing remaining bytes
- * and performing final mixing.
- *
- * @param hash The running hash
- * @param unprocessedLength The number of unprocessed bytes in the tail data.
- * @param unprocessed Up to 3 unprocessed bytes from input data.
- * @param totalLen The total number of input bytes added since the start.
- * @return The 32-bit hash
- */
- int finalise(final int hash, final int unprocessedLength, final byte[] unprocessed, final int totalLen) {
- int result = hash;
- int k1 = 0;
- switch (unprocessedLength) {
- case 3:
- k1 ^= (unprocessed[2] & 0xff) << 16;
- case 2:
- k1 ^= (unprocessed[1] & 0xff) << 8;
- case 1:
- k1 ^= unprocessed[0] & 0xff;
-
- // mix functions
- k1 *= C1_32;
- k1 = Integer.rotateLeft(k1, R1_32);
- k1 *= C2_32;
- result ^= k1;
- }
-
- // finalization
- result ^= totalLen;
- return fmix32(result);
- }
-
- /**
- * Combines the bytes using an Or operation ({@code | } in a little-endian representation
- * of a 32-bit integer; byte 1 will be the least significant byte, byte 4 the most
- * significant.
- *
- * @param b1 The first byte
- * @param b2 The second byte
- * @param b3 The third byte
- * @param b4 The fourth byte
- * @return The 32-bit integer
- */
- private static int orBytes(final byte b1, final byte b2, final byte b3, final byte b4) {
- return b1 & 0xff | (b2 & 0xff) << 8 | (b3 & 0xff) << 16 | (b4 & 0xff) << 24;
- }
- }
-
- /**
- * Generates 32-bit hash from input bytes. Bytes can be added incrementally and the new
- * hash computed.
- *
- * <p>This is an implementation of the 32-bit hash function {@code MurmurHash3_x86_32}
- * from Austin Appleby's original MurmurHash3 {@code c++} code in SMHasher.</p>
- *
- * <p>This implementation contains a sign-extension bug in the finalization step of
- * any bytes left over from dividing the length by 4. This manifests if any of these
- * bytes are negative.</p>
- *
- * @deprecated Use IncrementalHash32x86. This corrects the processing of trailing bytes.
- */
- @Deprecated
- public static class IncrementalHash32 extends IncrementalHash32x86 {
-
- /**
- * {@inheritDoc}
- *
- * <p>This implementation contains a sign-extension bug in the finalization step of
- * any bytes left over from dividing the length by 4. This manifests if any of these
- * bytes are negative.<p>
- *
- * @deprecated Use IncrementalHash32x86. This corrects the processing of trailing bytes.
- */
- @Override
- @Deprecated
- int finalise(final int hash, final int unprocessedLength, final byte[] unprocessed, final int totalLen) {
- int result = hash;
- // ************
- // Note: This fails to apply masking using 0xff to the 3 remaining bytes.
- // ************
- int k1 = 0;
- switch (unprocessedLength) {
- case 3:
- k1 ^= unprocessed[2] << 16;
- case 2:
- k1 ^= unprocessed[1] << 8;
- case 1:
- k1 ^= unprocessed[0];
-
- // mix functions
- k1 *= C1_32;
- k1 = Integer.rotateLeft(k1, R1_32);
- k1 *= C2_32;
- result ^= k1;
- }
-
- // finalization
- result ^= totalLen;
- return fmix32(result);
- }
+ /** No instance methods. */
+ private MurmurHash3() {
}
}
diff --git a/src/main/java/org/apache/commons/codec/digest/UnixCrypt.java b/src/main/java/org/apache/commons/codec/digest/UnixCrypt.java
index cb814246..8d83a6a7 100644
--- a/src/main/java/org/apache/commons/codec/digest/UnixCrypt.java
+++ b/src/main/java/org/apache/commons/codec/digest/UnixCrypt.java
@@ -172,6 +172,49 @@ public class UnixCrypt {
0x8000020, 0x208000, 32800, 0x8008020, 0x8200000, 32, 0x8208000, 0x208020, 0, 0x8000000,
0x8200020, 32768, 0x208020 } };
+ private static int[] body(final int[] schedule, final int eSwap0, final int eSwap1) {
+ int left = 0;
+ int right = 0;
+ int t = 0;
+ for (int j = 0; j < 25; j++) {
+ for (int i = 0; i < 32; i += 4) {
+ left = dEncrypt(left, right, i, eSwap0, eSwap1, schedule);
+ right = dEncrypt(right, left, i + 2, eSwap0, eSwap1, schedule);
+ }
+ t = left;
+ left = right;
+ right = t;
+ }
+
+ t = right;
+ right = left >>> 1 | left << 31;
+ left = t >>> 1 | t << 31;
+ final int[] results = new int[2];
+ permOp(right, left, 1, 0x55555555, results);
+ right = results[0];
+ left = results[1];
+ permOp(left, right, 8, 0xff00ff, results);
+ left = results[0];
+ right = results[1];
+ permOp(right, left, 2, 0x33333333, results);
+ right = results[0];
+ left = results[1];
+ permOp(left, right, 16, 65535, results);
+ left = results[0];
+ right = results[1];
+ permOp(right, left, 4, 0xf0f0f0f, results);
+ right = results[0];
+ left = results[1];
+ final int[] out = new int[2];
+ out[0] = left;
+ out[1] = right;
+ return out;
+ }
+
+ private static int byteToUnsigned(final byte b) {
+ return b & 0xff;
+ }
+
/**
* Generates a crypt(3) compatible hash using the DES algorithm.
* <p>
@@ -285,49 +328,6 @@ public class UnixCrypt {
return crypt(original.getBytes(StandardCharsets.UTF_8), salt);
}
- private static int[] body(final int[] schedule, final int eSwap0, final int eSwap1) {
- int left = 0;
- int right = 0;
- int t = 0;
- for (int j = 0; j < 25; j++) {
- for (int i = 0; i < 32; i += 4) {
- left = dEncrypt(left, right, i, eSwap0, eSwap1, schedule);
- right = dEncrypt(right, left, i + 2, eSwap0, eSwap1, schedule);
- }
- t = left;
- left = right;
- right = t;
- }
-
- t = right;
- right = left >>> 1 | left << 31;
- left = t >>> 1 | t << 31;
- final int[] results = new int[2];
- permOp(right, left, 1, 0x55555555, results);
- right = results[0];
- left = results[1];
- permOp(left, right, 8, 0xff00ff, results);
- left = results[0];
- right = results[1];
- permOp(right, left, 2, 0x33333333, results);
- right = results[0];
- left = results[1];
- permOp(left, right, 16, 65535, results);
- left = results[0];
- right = results[1];
- permOp(right, left, 4, 0xf0f0f0f, results);
- right = results[0];
- left = results[1];
- final int[] out = new int[2];
- out[0] = left;
- out[1] = right;
- return out;
- }
-
- private static int byteToUnsigned(final byte b) {
- return b & 0xff;
- }
-
private static int dEncrypt(int el, final int r, final int s, final int e0, final int e1, final int[] sArr) {
int v = r ^ r >>> 16;
int u = v & e0;
diff --git a/src/main/java/org/apache/commons/codec/digest/XXHash32.java b/src/main/java/org/apache/commons/codec/digest/XXHash32.java
index c11d3638..f2d4af8d 100644
--- a/src/main/java/org/apache/commons/codec/digest/XXHash32.java
+++ b/src/main/java/org/apache/commons/codec/digest/XXHash32.java
@@ -46,14 +46,28 @@ public class XXHash32 implements Checksum {
private static final int PRIME4 = 668265263;
private static final int PRIME5 = 374761393;
+ /**
+ * Gets the little-endian int from 4 bytes starting at the specified index.
+ *
+ * @param buffer The data
+ * @param idx The index
+ * @return The little-endian int
+ */
+ private static int getInt(final byte[] buffer, final int idx) {
+ return buffer[idx ] & 0xff |
+ (buffer[idx + 1] & 0xff) << 8 |
+ (buffer[idx + 2] & 0xff) << 16 |
+ (buffer[idx + 3] & 0xff) << 24;
+ }
private final byte[] oneByte = new byte[1];
private final int[] state = new int[4];
// Note: the code used to use ByteBuffer but the manual method is 50% faster
// See: http://gitbox.apache.org/repos/asf/commons-compress/diff/2f56fb5c
private final byte[] buffer = new byte[BUF_SIZE];
- private final int seed;
+ private final int seed;
private int totalLen;
+
private int pos;
/** Set to true when the state array has been updated since the last reset. */
@@ -75,61 +89,6 @@ public class XXHash32 implements Checksum {
initializeState();
}
- @Override
- public void reset() {
- initializeState();
- totalLen = 0;
- pos = 0;
- stateUpdated = false;
- }
-
- @Override
- public void update(final int b) {
- oneByte[0] = (byte) (b & 0xff);
- update(oneByte, 0, 1);
- }
-
- @Override
- public void update(final byte[] b, int off, final int len) {
- if (len <= 0) {
- return;
- }
- totalLen += len;
-
- final int end = off + len;
-
- // Check if the unprocessed bytes and new bytes can fill a block of 16.
- // Make this overflow safe in the event that len is Integer.MAX_VALUE.
- // Equivalent to: (pos + len < BUF_SIZE)
- if (pos + len - BUF_SIZE < 0) {
- System.arraycopy(b, off, buffer, pos, len);
- pos += len;
- return;
- }
-
- // Process left-over bytes with new bytes
- if (pos > 0) {
- final int size = BUF_SIZE - pos;
- System.arraycopy(b, off, buffer, pos, size);
- process(buffer, 0);
- off += size;
- }
-
- final int limit = end - BUF_SIZE;
- while (off <= limit) {
- process(b, off);
- off += BUF_SIZE;
- }
-
- // Handle left-over bytes
- if (off < end) {
- pos = end - off;
- System.arraycopy(b, off, buffer, 0, pos);
- } else {
- pos = 0;
- }
- }
-
@Override
public long getValue() {
int hash;
@@ -163,20 +122,6 @@ public class XXHash32 implements Checksum {
return hash & 0xffffffffL;
}
- /**
- * Gets the little-endian int from 4 bytes starting at the specified index.
- *
- * @param buffer The data
- * @param idx The index
- * @return The little-endian int
- */
- private static int getInt(final byte[] buffer, final int idx) {
- return buffer[idx ] & 0xff |
- (buffer[idx + 1] & 0xff) << 8 |
- (buffer[idx + 2] & 0xff) << 16 |
- (buffer[idx + 3] & 0xff) << 24;
- }
-
private void initializeState() {
state[0] = seed + PRIME1 + PRIME2;
state[1] = seed + PRIME2;
@@ -203,4 +148,59 @@ public class XXHash32 implements Checksum {
stateUpdated = true;
}
+
+ @Override
+ public void reset() {
+ initializeState();
+ totalLen = 0;
+ pos = 0;
+ stateUpdated = false;
+ }
+
+ @Override
+ public void update(final byte[] b, int off, final int len) {
+ if (len <= 0) {
+ return;
+ }
+ totalLen += len;
+
+ final int end = off + len;
+
+ // Check if the unprocessed bytes and new bytes can fill a block of 16.
+ // Make this overflow safe in the event that len is Integer.MAX_VALUE.
+ // Equivalent to: (pos + len < BUF_SIZE)
+ if (pos + len - BUF_SIZE < 0) {
+ System.arraycopy(b, off, buffer, pos, len);
+ pos += len;
+ return;
+ }
+
+ // Process left-over bytes with new bytes
+ if (pos > 0) {
+ final int size = BUF_SIZE - pos;
+ System.arraycopy(b, off, buffer, pos, size);
+ process(buffer, 0);
+ off += size;
+ }
+
+ final int limit = end - BUF_SIZE;
+ while (off <= limit) {
+ process(b, off);
+ off += BUF_SIZE;
+ }
+
+ // Handle left-over bytes
+ if (off < end) {
+ pos = end - off;
+ System.arraycopy(b, off, buffer, 0, pos);
+ } else {
+ pos = 0;
+ }
+ }
+
+ @Override
+ public void update(final int b) {
+ oneByte[0] = (byte) (b & 0xff);
+ update(oneByte, 0, 1);
+ }
}
diff --git a/src/main/java/org/apache/commons/codec/language/ColognePhonetic.java b/src/main/java/org/apache/commons/codec/language/ColognePhonetic.java
index bd1c59cf..0a7b6271 100644
--- a/src/main/java/org/apache/commons/codec/language/ColognePhonetic.java
+++ b/src/main/java/org/apache/commons/codec/language/ColognePhonetic.java
@@ -182,19 +182,6 @@ import org.apache.commons.codec.StringEncoder;
*/
public class ColognePhonetic implements StringEncoder {
- // Predefined char arrays for better performance and less GC load
- private static final char[] AEIJOUY = { 'A', 'E', 'I', 'J', 'O', 'U', 'Y' };
- private static final char[] CSZ = { 'C', 'S', 'Z' };
- private static final char[] FPVW = { 'F', 'P', 'V', 'W' };
- private static final char[] GKQ = { 'G', 'K', 'Q' };
- private static final char[] CKQ = { 'C', 'K', 'Q' };
- private static final char[] AHKLOQRUX = { 'A', 'H', 'K', 'L', 'O', 'Q', 'R', 'U', 'X' };
- private static final char[] SZ = { 'S', 'Z' };
- private static final char[] AHKOQUX = { 'A', 'H', 'K', 'O', 'Q', 'U', 'X' };
- private static final char[] DTX = { 'D', 'T', 'X' };
-
- private static final char CHAR_IGNORE = '-'; // is this character to be ignored?
-
/**
* This class is not thread-safe; the field {@link #length} is mutable.
* However, it is not shared between threads, as it is constructed on demand
@@ -218,6 +205,10 @@ public class ColognePhonetic implements StringEncoder {
protected abstract char[] copyData(int start, int length);
+ public boolean isEmpty() {
+ return length() == 0;
+ }
+
public int length() {
return length;
}
@@ -226,12 +217,34 @@ public class ColognePhonetic implements StringEncoder {
public String toString() {
return new String(copyData(0, length));
}
+ }
+ private class CologneInputBuffer extends CologneBuffer {
- public boolean isEmpty() {
- return length() == 0;
+ public CologneInputBuffer(final char[] data) {
+ super(data);
+ }
+
+ @Override
+ protected char[] copyData(final int start, final int length) {
+ final char[] newData = new char[length];
+ System.arraycopy(data, data.length - this.length + start, newData, 0, length);
+ return newData;
+ }
+
+ public char getNextChar() {
+ return data[getNextPos()];
+ }
+
+ protected int getNextPos() {
+ return data.length - length;
}
- }
+ public char removeNext() {
+ final char ch = getNextChar();
+ length--;
+ return ch;
+ }
+ }
private class CologneOutputBuffer extends CologneBuffer {
private char lastCode;
@@ -241,6 +254,11 @@ public class ColognePhonetic implements StringEncoder {
lastCode = '/'; // impossible value
}
+ @Override
+ protected char[] copyData(final int start, final int length) {
+ return Arrays.copyOfRange(data, start, length);
+ }
+
/**
* Stores the next code in the output buffer, keeping track of the previous code.
* '0' is only stored if it is the first entry.
@@ -256,40 +274,22 @@ public class ColognePhonetic implements StringEncoder {
}
lastCode = code;
}
-
- @Override
- protected char[] copyData(final int start, final int length) {
- return Arrays.copyOfRange(data, start, length);
- }
}
+ // Predefined char arrays for better performance and less GC load
+ private static final char[] AEIJOUY = { 'A', 'E', 'I', 'J', 'O', 'U', 'Y' };
+ private static final char[] CSZ = { 'C', 'S', 'Z' };
+ private static final char[] FPVW = { 'F', 'P', 'V', 'W' };
+ private static final char[] GKQ = { 'G', 'K', 'Q' };
+ private static final char[] CKQ = { 'C', 'K', 'Q' };
+ private static final char[] AHKLOQRUX = { 'A', 'H', 'K', 'L', 'O', 'Q', 'R', 'U', 'X' };
- private class CologneInputBuffer extends CologneBuffer {
-
- public CologneInputBuffer(final char[] data) {
- super(data);
- }
-
- @Override
- protected char[] copyData(final int start, final int length) {
- final char[] newData = new char[length];
- System.arraycopy(data, data.length - this.length + start, newData, 0, length);
- return newData;
- }
+ private static final char[] SZ = { 'S', 'Z' };
- public char getNextChar() {
- return data[getNextPos()];
- }
+ private static final char[] AHKOQUX = { 'A', 'H', 'K', 'O', 'Q', 'U', 'X' };
- protected int getNextPos() {
- return data.length - length;
- }
+ private static final char[] DTX = { 'D', 'T', 'X' };
- public char removeNext() {
- final char ch = getNextChar();
- length--;
- return ch;
- }
- }
+ private static final char CHAR_IGNORE = '-'; // is this character to be ignored?
/*
* Returns whether the array contains the key, or not.
diff --git a/src/main/java/org/apache/commons/codec/language/DaitchMokotoffSoundex.java b/src/main/java/org/apache/commons/codec/language/DaitchMokotoffSoundex.java
index 96390df4..79d4680c 100644
--- a/src/main/java/org/apache/commons/codec/language/DaitchMokotoffSoundex.java
+++ b/src/main/java/org/apache/commons/codec/language/DaitchMokotoffSoundex.java
@@ -69,29 +69,6 @@ import org.apache.commons.codec.StringEncoder;
*/
public class DaitchMokotoffSoundex implements StringEncoder {
- private static final String COMMENT = "//";
-
- private static final String DOUBLE_QUOTE = "\"";
-
- private static final String MULTILINE_COMMENT_END = "*/";
-
- private static final String MULTILINE_COMMENT_START = "/*";
-
- /** The resource file containing the replacement and folding rules */
- private static final String RESOURCE_FILE = "org/apache/commons/codec/language/dmrules.txt";
-
- /** The code length of a DM soundex value. */
- private static final int MAX_LENGTH = 6;
-
- /** Transformation rules indexed by the first character of their pattern. */
- private static final Map<Character, List<Rule>> RULES = new HashMap<>();
-
- /** Folding rules. */
- private static final Map<Character, Character> FOLDINGS = new HashMap<>();
-
- /** Whether to use ASCII folding prior to encoding. */
- private final boolean folding;
-
/**
* Inner class representing a branch during DM soundex encoding.
*/
@@ -227,6 +204,26 @@ public class DaitchMokotoffSoundex implements StringEncoder {
}
}
+ private static final String COMMENT = "//";
+
+ private static final String DOUBLE_QUOTE = "\"";
+
+ private static final String MULTILINE_COMMENT_END = "*/";
+
+ private static final String MULTILINE_COMMENT_START = "/*";
+
+ /** The resource file containing the replacement and folding rules */
+ private static final String RESOURCE_FILE = "org/apache/commons/codec/language/dmrules.txt";
+
+ /** The code length of a DM soundex value. */
+ private static final int MAX_LENGTH = 6;
+
+ /** Transformation rules indexed by the first character of their pattern. */
+ private static final Map<Character, List<Rule>> RULES = new HashMap<>();
+
+ /** Folding rules. */
+ private static final Map<Character, Character> FOLDINGS = new HashMap<>();
+
static {
try (final Scanner scanner = new Scanner(Resources.getInputStream(RESOURCE_FILE), CharEncoding.UTF_8)) {
parseRules(scanner, RESOURCE_FILE, RULES, FOLDINGS);
@@ -323,6 +320,9 @@ public class DaitchMokotoffSoundex implements StringEncoder {
return str;
}
+ /** Whether to use ASCII folding prior to encoding. */
+ private final boolean folding;
+
/**
* Creates a new instance with ASCII-folding enabled.
*/
diff --git a/src/main/java/org/apache/commons/codec/language/DoubleMetaphone.java b/src/main/java/org/apache/commons/codec/language/DoubleMetaphone.java
index 4c11b2cb..44a68977 100644
--- a/src/main/java/org/apache/commons/codec/language/DoubleMetaphone.java
+++ b/src/main/java/org/apache/commons/codec/language/DoubleMetaphone.java
@@ -36,11 +36,87 @@ import org.apache.commons.codec.binary.StringUtils;
*/
public class DoubleMetaphone implements StringEncoder {
+ /**
+ * Inner class for storing results, since there is the optional alternate encoding.
+ */
+ public class DoubleMetaphoneResult {
+
+ private final StringBuilder primary = new StringBuilder(getMaxCodeLen());
+ private final StringBuilder alternate = new StringBuilder(getMaxCodeLen());
+ private final int maxLength;
+
+ public DoubleMetaphoneResult(final int maxLength) {
+ this.maxLength = maxLength;
+ }
+
+ public void append(final char value) {
+ appendPrimary(value);
+ appendAlternate(value);
+ }
+
+ public void append(final char primary, final char alternate) {
+ appendPrimary(primary);
+ appendAlternate(alternate);
+ }
+
+ public void append(final String value) {
+ appendPrimary(value);
+ appendAlternate(value);
+ }
+
+ public void append(final String primary, final String alternate) {
+ appendPrimary(primary);
+ appendAlternate(alternate);
+ }
+
+ public void appendAlternate(final char value) {
+ if (this.alternate.length() < this.maxLength) {
+ this.alternate.append(value);
+ }
+ }
+
+ public void appendAlternate(final String value) {
+ final int addChars = this.maxLength - this.alternate.length();
+ if (value.length() <= addChars) {
+ this.alternate.append(value);
+ } else {
+ this.alternate.append(value, 0, addChars);
+ }
+ }
+
+ public void appendPrimary(final char value) {
+ if (this.primary.length() < this.maxLength) {
+ this.primary.append(value);
+ }
+ }
+
+ public void appendPrimary(final String value) {
+ final int addChars = this.maxLength - this.primary.length();
+ if (value.length() <= addChars) {
+ this.primary.append(value);
+ } else {
+ this.primary.append(value, 0, addChars);
+ }
+ }
+
+ public String getAlternate() {
+ return this.alternate.toString();
+ }
+
+ public String getPrimary() {
+ return this.primary.toString();
+ }
+
+ public boolean isComplete() {
+ return this.primary.length() >= this.maxLength &&
+ this.alternate.length() >= this.maxLength;
+ }
+ }
+
/**
* "Vowels" to test for
*/
private static final String VOWELS = "AEIOUY";
-
/**
* Prefixes when present which are not pronounced
*/
@@ -50,14 +126,133 @@ public class DoubleMetaphone implements StringEncoder {
{ "L", "R", "N", "M", "B", "H", "F", "V", "W", " " };
private static final String[] ES_EP_EB_EL_EY_IB_IL_IN_IE_EI_ER =
{ "ES", "EP", "EB", "EL", "EY", "IB", "IL", "IN", "IE", "EI", "ER" };
+
private static final String[] L_T_K_S_N_M_B_Z =
{ "L", "T", "K", "S", "N", "M", "B", "Z" };
+ /*
+ * Determines whether {@code value} contains any of the criteria starting at index {@code start} and
+ * matching up to length {@code length}.
+ */
+ protected static boolean contains(final String value, final int start, final int length,
+ final String... criteria) {
+ boolean result = false;
+ if (start >= 0 && start + length <= value.length()) {
+ final String target = value.substring(start, start + length);
+
+ for (final String element : criteria) {
+ if (target.equals(element)) {
+ result = true;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
/**
* Maximum length of an encoding, default is 4
*/
private int maxCodeLen = 4;
+ /*
+ * Gets the character at index {@code index} if available, otherwise
+ * it returns {@code Character.MIN_VALUE} so that there is some sort
+ * of default.
+ */
+ protected char charAt(final String value, final int index) {
+ if (index < 0 || index >= value.length()) {
+ return Character.MIN_VALUE;
+ }
+ return value.charAt(index);
+ }
+
+ /**
+ * Cleans the input.
+ */
+ private String cleanInput(String input) {
+ if (input == null) {
+ return null;
+ }
+ input = input.trim();
+ if (input.isEmpty()) {
+ return null;
+ }
+ return input.toUpperCase(java.util.Locale.ENGLISH);
+ }
+
+ /**
+ * Complex condition 0 for 'C'.
+ */
+ private boolean conditionC0(final String value, final int index) {
+ if (contains(value, index, 4, "CHIA")) {
+ return true;
+ }
+ if (index <= 1) {
+ return false;
+ }
+ if (isVowel(charAt(value, index - 2))) {
+ return false;
+ }
+ if (!contains(value, index - 1, 3, "ACH")) {
+ return false;
+ }
+ final char c = charAt(value, index + 2);
+ return c != 'I' && c != 'E' ||
+ contains(value, index - 2, 6, "BACHER", "MACHER");
+ }
+
+ /**
+ * Complex condition 0 for 'CH'.
+ */
+ private boolean conditionCH0(final String value, final int index) {
+ if (index != 0) {
+ return false;
+ }
+ if (!contains(value, index + 1, 5, "HARAC", "HARIS") &&
+ !contains(value, index + 1, 3, "HOR", "HYM", "HIA", "HEM")) {
+ return false;
+ }
+ return !contains(value, 0, 5, "CHORE");
+ }
+
+ /**
+ * Complex condition 1 for 'CH'.
+ */
+ private boolean conditionCH1(final String value, final int index) {
+ return contains(value, 0, 4, "VAN ", "VON ") || contains(value, 0, 3, "SCH") ||
+ contains(value, index - 2, 6, "ORCHES", "ARCHIT", "ORCHID") ||
+ contains(value, index + 2, 1, "T", "S") ||
+ (contains(value, index - 1, 1, "A", "O", "U", "E") || index == 0) &&
+ (contains(value, index + 2, 1, L_R_N_M_B_H_F_V_W_SPACE) || index + 1 == value.length() - 1);
+ }
+
+ /**
+ * Complex condition 0 for 'L'.
+ */
+ private boolean conditionL0(final String value, final int index) {
+ if (index == value.length() - 3 &&
+ contains(value, index - 1, 4, "ILLO", "ILLA", "ALLE")) {
+ return true;
+ }
+ return (contains(value, value.length() - 2, 2, "AS", "OS") ||
+ contains(value, value.length() - 1, 1, "A", "O")) &&
+ contains(value, index - 1, 4, "ALLE");
+ }
+
+ //-- BEGIN HANDLERS --//
+
+ /**
+ * Complex condition 0 for 'M'.
+ */
+ private boolean conditionM0(final String value, final int index) {
+ if (charAt(value, index + 1) == 'M') {
+ return true;
+ }
+ return contains(value, index - 1, 3, "UMB") &&
+ (index + 1 == value.length() - 1 || contains(value, index + 2, 2, "ER"));
+ }
+
/**
* Encode a value with Double Metaphone.
*
@@ -209,34 +404,6 @@ public class DoubleMetaphone implements StringEncoder {
return doubleMetaphone(value);
}
- /**
- * Check if the Double Metaphone values of two {@code String} values
- * are equal.
- *
- * @param value1 The left-hand side of the encoded {@link String#equals(Object)}.
- * @param value2 The right-hand side of the encoded {@link String#equals(Object)}.
- * @return {@code true} if the encoded {@code String}s are equal;
- * {@code false} otherwise.
- * @see #isDoubleMetaphoneEqual(String,String,boolean)
- */
- public boolean isDoubleMetaphoneEqual(final String value1, final String value2) {
- return isDoubleMetaphoneEqual(value1, value2, false);
- }
-
- /**
- * Check if the Double Metaphone values of two {@code String} values
- * are equal, optionally using the alternate value.
- *
- * @param value1 The left-hand side of the encoded {@link String#equals(Object)}.
- * @param value2 The right-hand side of the encoded {@link String#equals(Object)}.
- * @param alternate use the alternate value if {@code true}.
- * @return {@code true} if the encoded {@code String}s are equal;
- * {@code false} otherwise.
- */
- public boolean isDoubleMetaphoneEqual(final String value1, final String value2, final boolean alternate) {
- return StringUtils.equals(doubleMetaphone(value1, alternate), doubleMetaphone(value2, alternate));
- }
-
/**
* Returns the maxCodeLen.
* @return int
@@ -245,16 +412,6 @@ public class DoubleMetaphone implements StringEncoder {
return this.maxCodeLen;
}
- /**
- * Sets the maxCodeLen.
- * @param maxCodeLen The maxCodeLen to set
- */
- public void setMaxCodeLen(final int maxCodeLen) {
- this.maxCodeLen = maxCodeLen;
- }
-
- //-- BEGIN HANDLERS --//
-
/**
* Handles 'A', 'E', 'I', 'O', 'U', and 'Y' cases.
*/
@@ -584,6 +741,8 @@ public class DoubleMetaphone implements StringEncoder {
return charAt(value, index + 1) == 'R' ? index + 2 : index + 1;
}
+ //-- BEGIN CONDITIONS --//
+
/**
* Handles 'S' cases.
*/
@@ -738,6 +897,8 @@ public class DoubleMetaphone implements StringEncoder {
return index;
}
+ //-- BEGIN HELPER FUNCTIONS --//
+
/**
* Handles 'Z' cases.
*/
@@ -759,94 +920,32 @@ public class DoubleMetaphone implements StringEncoder {
return index;
}
- //-- BEGIN CONDITIONS --//
-
- /**
- * Complex condition 0 for 'C'.
- */
- private boolean conditionC0(final String value, final int index) {
- if (contains(value, index, 4, "CHIA")) {
- return true;
- }
- if (index <= 1) {
- return false;
- }
- if (isVowel(charAt(value, index - 2))) {
- return false;
- }
- if (!contains(value, index - 1, 3, "ACH")) {
- return false;
- }
- final char c = charAt(value, index + 2);
- return c != 'I' && c != 'E' ||
- contains(value, index - 2, 6, "BACHER", "MACHER");
- }
-
/**
- * Complex condition 0 for 'CH'.
- */
- private boolean conditionCH0(final String value, final int index) {
- if (index != 0) {
- return false;
- }
- if (!contains(value, index + 1, 5, "HARAC", "HARIS") &&
- !contains(value, index + 1, 3, "HOR", "HYM", "HIA", "HEM")) {
- return false;
- }
- return !contains(value, 0, 5, "CHORE");
- }
-
- /**
- * Complex condition 1 for 'CH'.
- */
- private boolean conditionCH1(final String value, final int index) {
- return contains(value, 0, 4, "VAN ", "VON ") || contains(value, 0, 3, "SCH") ||
- contains(value, index - 2, 6, "ORCHES", "ARCHIT", "ORCHID") ||
- contains(value, index + 2, 1, "T", "S") ||
- (contains(value, index - 1, 1, "A", "O", "U", "E") || index == 0) &&
- (contains(value, index + 2, 1, L_R_N_M_B_H_F_V_W_SPACE) || index + 1 == value.length() - 1);
- }
-
- /**
- * Complex condition 0 for 'L'.
- */
- private boolean conditionL0(final String value, final int index) {
- if (index == value.length() - 3 &&
- contains(value, index - 1, 4, "ILLO", "ILLA", "ALLE")) {
- return true;
- }
- return (contains(value, value.length() - 2, 2, "AS", "OS") ||
- contains(value, value.length() - 1, 1, "A", "O")) &&
- contains(value, index - 1, 4, "ALLE");
- }
-
- /**
- * Complex condition 0 for 'M'.
- */
- private boolean conditionM0(final String value, final int index) {
- if (charAt(value, index + 1) == 'M') {
- return true;
- }
- return contains(value, index - 1, 3, "UMB") &&
- (index + 1 == value.length() - 1 || contains(value, index + 2, 2, "ER"));
- }
-
- //-- BEGIN HELPER FUNCTIONS --//
-
- /**
- * Determines whether or not a value is of slavo-germanic origin. A value is
- * of slavo-germanic origin if it contians any of 'W', 'K', 'CZ', or 'WITZ'.
+ * Check if the Double Metaphone values of two {@code String} values
+ * are equal.
+ *
+ * @param value1 The left-hand side of the encoded {@link String#equals(Object)}.
+ * @param value2 The right-hand side of the encoded {@link String#equals(Object)}.
+ * @return {@code true} if the encoded {@code String}s are equal;
+ * {@code false} otherwise.
+ * @see #isDoubleMetaphoneEqual(String,String,boolean)
*/
- private boolean isSlavoGermanic(final String value) {
- return value.indexOf('W') > -1 || value.indexOf('K') > -1 ||
- value.contains("CZ") || value.contains("WITZ");
+ public boolean isDoubleMetaphoneEqual(final String value1, final String value2) {
+ return isDoubleMetaphoneEqual(value1, value2, false);
}
/**
- * Determines whether or not a character is a vowel or not
+ * Check if the Double Metaphone values of two {@code String} values
+ * are equal, optionally using the alternate value.
+ *
+ * @param value1 The left-hand side of the encoded {@link String#equals(Object)}.
+ * @param value2 The right-hand side of the encoded {@link String#equals(Object)}.
+ * @param alternate use the alternate value if {@code true}.
+ * @return {@code true} if the encoded {@code String}s are equal;
+ * {@code false} otherwise.
*/
- private boolean isVowel(final char ch) {
- return VOWELS.indexOf(ch) != -1;
+ public boolean isDoubleMetaphoneEqual(final String value1, final String value2, final boolean alternate) {
+ return StringUtils.equals(doubleMetaphone(value1, alternate), doubleMetaphone(value2, alternate));
}
/**
@@ -866,127 +965,28 @@ public class DoubleMetaphone implements StringEncoder {
}
/**
- * Cleans the input.
- */
- private String cleanInput(String input) {
- if (input == null) {
- return null;
- }
- input = input.trim();
- if (input.isEmpty()) {
- return null;
- }
- return input.toUpperCase(java.util.Locale.ENGLISH);
- }
-
- /*
- * Gets the character at index {@code index} if available, otherwise
- * it returns {@code Character.MIN_VALUE} so that there is some sort
- * of default.
+ * Determines whether or not a value is of slavo-germanic origin. A value is
+ * of slavo-germanic origin if it contians any of 'W', 'K', 'CZ', or 'WITZ'.
*/
- protected char charAt(final String value, final int index) {
- if (index < 0 || index >= value.length()) {
- return Character.MIN_VALUE;
- }
- return value.charAt(index);
+ private boolean isSlavoGermanic(final String value) {
+ return value.indexOf('W') > -1 || value.indexOf('K') > -1 ||
+ value.contains("CZ") || value.contains("WITZ");
}
- /*
- * Determines whether {@code value} contains any of the criteria starting at index {@code start} and
- * matching up to length {@code length}.
+ /**
+ * Determines whether or not a character is a vowel or not
*/
- protected static boolean contains(final String value, final int start, final int length,
- final String... criteria) {
- boolean result = false;
- if (start >= 0 && start + length <= value.length()) {
- final String target = value.substring(start, start + length);
-
- for (final String element : criteria) {
- if (target.equals(element)) {
- result = true;
- break;
- }
- }
- }
- return result;
+ private boolean isVowel(final char ch) {
+ return VOWELS.indexOf(ch) != -1;
}
//-- BEGIN INNER CLASSES --//
/**
- * Inner class for storing results, since there is the optional alternate encoding.
+ * Sets the maxCodeLen.
+ * @param maxCodeLen The maxCodeLen to set
*/
- public class DoubleMetaphoneResult {
-
- private final StringBuilder primary = new StringBuilder(getMaxCodeLen());
- private final StringBuilder alternate = new StringBuilder(getMaxCodeLen());
- private final int maxLength;
-
- public DoubleMetaphoneResult(final int maxLength) {
- this.maxLength = maxLength;
- }
-
- public void append(final char value) {
- appendPrimary(value);
- appendAlternate(value);
- }
-
- public void append(final char primary, final char alternate) {
- appendPrimary(primary);
- appendAlternate(alternate);
- }
-
- public void appendPrimary(final char value) {
- if (this.primary.length() < this.maxLength) {
- this.primary.append(value);
- }
- }
-
- public void appendAlternate(final char value) {
- if (this.alternate.length() < this.maxLength) {
- this.alternate.append(value);
- }
- }
-
- public void append(final String value) {
- appendPrimary(value);
- appendAlternate(value);
- }
-
- public void append(final String primary, final String alternate) {
- appendPrimary(primary);
- appendAlternate(alternate);
- }
-
- public void appendPrimary(final String value) {
- final int addChars = this.maxLength - this.primary.length();
- if (value.length() <= addChars) {
- this.primary.append(value);
- } else {
- this.primary.append(value, 0, addChars);
- }
- }
-
- public void appendAlternate(final String value) {
- final int addChars = this.maxLength - this.alternate.length();
- if (value.length() <= addChars) {
- this.alternate.append(value);
- } else {
- this.alternate.append(value, 0, addChars);
- }
- }
-
- public String getPrimary() {
- return this.primary.toString();
- }
-
- public String getAlternate() {
- return this.alternate.toString();
- }
-
- public boolean isComplete() {
- return this.primary.length() >= this.maxLength &&
- this.alternate.length() >= this.maxLength;
- }
+ public void setMaxCodeLen(final int maxCodeLen) {
+ this.maxCodeLen = maxCodeLen;
}
}
diff --git a/src/main/java/org/apache/commons/codec/language/Metaphone.java b/src/main/java/org/apache/commons/codec/language/Metaphone.java
index ff23ac59..bf055587 100644
--- a/src/main/java/org/apache/commons/codec/language/Metaphone.java
+++ b/src/main/java/org/apache/commons/codec/language/Metaphone.java
@@ -74,6 +74,81 @@ public class Metaphone implements StringEncoder {
*/
private int maxCodeLen = 4;
+ /**
+ * Encodes an Object using the metaphone algorithm. This method
+ * is provided in order to satisfy the requirements of the
+ * Encoder interface, and will throw an EncoderException if the
+ * supplied object is not of type java.lang.String.
+ *
+ * @param obj Object to encode
+ * @return An object (or type java.lang.String) containing the
+ * metaphone code which corresponds to the String supplied.
+ * @throws EncoderException if the parameter supplied is not
+ * of type java.lang.String
+ */
+ @Override
+ public Object encode(final Object obj) throws EncoderException {
+ if (!(obj instanceof String)) {
+ throw new EncoderException("Parameter supplied to Metaphone encode is not of type java.lang.String");
+ }
+ return metaphone((String) obj);
+ }
+
+ /**
+ * Encodes a String using the Metaphone algorithm.
+ *
+ * @param str String object to encode
+ * @return The metaphone code corresponding to the String supplied
+ */
+ @Override
+ public String encode(final String str) {
+ return metaphone(str);
+ }
+
+ /**
+ * Returns the maxCodeLen.
+ * @return int
+ */
+ public int getMaxCodeLen() { return this.maxCodeLen; }
+
+ private boolean isLastChar(final int wdsz, final int n) {
+ return n + 1 == wdsz;
+ }
+
+ /**
+ * Tests is the metaphones of two strings are identical.
+ *
+ * @param str1 First of two strings to compare
+ * @param str2 Second of two strings to compare
+ * @return {@code true} if the metaphones of these strings are identical,
+ * {@code false} otherwise.
+ */
+ public boolean isMetaphoneEqual(final String str1, final String str2) {
+ return metaphone(str1).equals(metaphone(str2));
+ }
+
+ private boolean isNextChar(final StringBuilder string, final int index, final char c) {
+ boolean matches = false;
+ if (index >= 0 &&
+ index < string.length() - 1 ) {
+ matches = string.charAt(index + 1) == c;
+ }
+ return matches;
+ }
+
+ private boolean isPreviousChar(final StringBuilder string, final int index, final char c) {
+ boolean matches = false;
+ if (index > 0 &&
+ index < string.length() ) {
+ matches = string.charAt(index - 1) == c;
+ }
+ return matches;
+ }
+
+ private boolean isVowel(final StringBuilder string, final int index) {
+ return VOWELS.indexOf(string.charAt(index)) >= 0;
+ }
+
/**
* Find the metaphone value of a String. This is similar to the
* soundex algorithm, but better at finding similar sounding words.
@@ -306,28 +381,6 @@ public class Metaphone implements StringEncoder {
return code.toString();
}
- private boolean isVowel(final StringBuilder string, final int index) {
- return VOWELS.indexOf(string.charAt(index)) >= 0;
- }
-
- private boolean isPreviousChar(final StringBuilder string, final int index, final char c) {
- boolean matches = false;
- if (index > 0 &&
- index < string.length() ) {
- matches = string.charAt(index - 1) == c;
- }
- return matches;
- }
-
- private boolean isNextChar(final StringBuilder string, final int index, final char c) {
- boolean matches = false;
- if (index >= 0 &&
- index < string.length() - 1 ) {
- matches = string.charAt(index + 1) == c;
- }
- return matches;
- }
-
private boolean regionMatch(final StringBuilder string, final int index, final String test) {
boolean matches = false;
if (index >= 0 && index + test.length() - 1 < string.length()) {
@@ -337,59 +390,6 @@ public class Metaphone implements StringEncoder {
return matches;
}
- private boolean isLastChar(final int wdsz, final int n) {
- return n + 1 == wdsz;
- }
-
- /**
- * Encodes an Object using the metaphone algorithm. This method
- * is provided in order to satisfy the requirements of the
- * Encoder interface, and will throw an EncoderException if the
- * supplied object is not of type java.lang.String.
- *
- * @param obj Object to encode
- * @return An object (or type java.lang.String) containing the
- * metaphone code which corresponds to the String supplied.
- * @throws EncoderException if the parameter supplied is not
- * of type java.lang.String
- */
- @Override
- public Object encode(final Object obj) throws EncoderException {
- if (!(obj instanceof String)) {
- throw new EncoderException("Parameter supplied to Metaphone encode is not of type java.lang.String");
- }
- return metaphone((String) obj);
- }
-
- /**
- * Encodes a String using the Metaphone algorithm.
- *
- * @param str String object to encode
- * @return The metaphone code corresponding to the String supplied
- */
- @Override
- public String encode(final String str) {
- return metaphone(str);
- }
-
- /**
- * Tests is the metaphones of two strings are identical.
- *
- * @param str1 First of two strings to compare
- * @param str2 Second of two strings to compare
- * @return {@code true} if the metaphones of these strings are identical,
- * {@code false} otherwise.
- */
- public boolean isMetaphoneEqual(final String str1, final String str2) {
- return metaphone(str1).equals(metaphone(str2));
- }
-
- /**
- * Returns the maxCodeLen.
- * @return int
- */
- public int getMaxCodeLen() { return this.maxCodeLen; }
-
/**
* Sets the maxCodeLen.
* @param maxCodeLen The maxCodeLen to set
diff --git a/src/main/java/org/apache/commons/codec/language/Nysiis.java b/src/main/java/org/apache/commons/codec/language/Nysiis.java
index 36b42412..969c6a58 100644
--- a/src/main/java/org/apache/commons/codec/language/Nysiis.java
+++ b/src/main/java/org/apache/commons/codec/language/Nysiis.java
@@ -92,9 +92,6 @@ public class Nysiis implements StringEncoder {
private static final char SPACE = ' ';
private static final int TRUE_LENGTH = 6;
- /** Indicates the strict mode. */
- private final boolean strict;
-
/**
* Tests if the given character is a vowel.
*
@@ -174,6 +171,9 @@ public class Nysiis implements StringEncoder {
return new char[] { curr };
}
+ /** Indicates the strict mode. */
+ private final boolean strict;
+
/**
* Creates an instance of the {@link Nysiis} encoder with strict mode (original form),
* i.e. encoded strings have a maximum length of 6.
diff --git a/src/main/java/org/apache/commons/codec/language/RefinedSoundex.java b/src/main/java/org/apache/commons/codec/language/RefinedSoundex.java
index 56cd0b42..30c7df91 100644
--- a/src/main/java/org/apache/commons/codec/language/RefinedSoundex.java
+++ b/src/main/java/org/apache/commons/codec/language/RefinedSoundex.java
@@ -55,6 +55,12 @@ public class RefinedSoundex implements StringEncoder {
*/
private static final char[] US_ENGLISH_MAPPING = US_ENGLISH_MAPPING_STRING.toCharArray();
+ /**
+ * This static variable contains an instance of the RefinedSoundex using
+ * the US_ENGLISH mapping.
+ */
+ public static final RefinedSoundex US_ENGLISH = new RefinedSoundex();
+
/**
* Every letter of the alphabet is "mapped" to a numerical value. This char
* array holds the values to which each letter is mapped. This
@@ -62,12 +68,6 @@ public class RefinedSoundex implements StringEncoder {
*/
private final char[] soundexMapping;
- /**
- * This static variable contains an instance of the RefinedSoundex using
- * the US_ENGLISH mapping.
- */
- public static final RefinedSoundex US_ENGLISH = new RefinedSoundex();
-
/**
* Creates an instance of the RefinedSoundex object using the default US
* English mapping.
diff --git a/src/main/java/org/apache/commons/codec/language/Soundex.java b/src/main/java/org/apache/commons/codec/language/Soundex.java
index 8905555d..2a00cddc 100644
--- a/src/main/java/org/apache/commons/codec/language/Soundex.java
+++ b/src/main/java/org/apache/commons/codec/language/Soundex.java
@@ -164,15 +164,6 @@ public class Soundex implements StringEncoder {
this.specialCaseHW = !hasMarker(this.soundexMapping);
}
- private boolean hasMarker(final char[] mapping) {
- for(final char ch : mapping) {
- if (ch == SILENT_MARKER) {
- return true;
- }
- }
- return false;
- }
-
/**
* Creates a refined soundex instance using a custom mapping. This constructor can be used to customize the mapping,
* and/or possibly provide an internationalized mapping for a non-Western character set.
@@ -272,6 +263,15 @@ public class Soundex implements StringEncoder {
return this.maxLength;
}
+ private boolean hasMarker(final char[] mapping) {
+ for(final char ch : mapping) {
+ if (ch == SILENT_MARKER) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Maps the given upper-case character to its Soundex code.
*
diff --git a/src/main/java/org/apache/commons/codec/language/bm/BeiderMorseEncoder.java b/src/main/java/org/apache/commons/codec/language/bm/BeiderMorseEncoder.java
index 21ae48c6..1cac30a0 100644
--- a/src/main/java/org/apache/commons/codec/language/bm/BeiderMorseEncoder.java
+++ b/src/main/java/org/apache/commons/codec/language/bm/BeiderMorseEncoder.java
@@ -143,6 +143,20 @@ public class BeiderMorseEncoder implements StringEncoder {
this.engine.getMaxPhonemes());
}
+ /**
+ * Sets the number of maximum of phonemes that shall be considered by the engine.
+ *
+ * @param maxPhonemes
+ * the maximum number of phonemes returned by the engine
+ * @since 1.7
+ */
+ public void setMaxPhonemes(final int maxPhonemes) {
+ this.engine = new PhoneticEngine(this.engine.getNameType(),
+ this.engine.getRuleType(),
+ this.engine.isConcat(),
+ maxPhonemes);
+ }
+
/**
* Sets the type of name. Use {@link NameType#GENERIC} unless you specifically want phonetic encodings
* optimized for Ashkenazi or Sephardic Jewish family names.
@@ -170,18 +184,4 @@ public class BeiderMorseEncoder implements StringEncoder {
this.engine.getMaxPhonemes());
}
- /**
- * Sets the number of maximum of phonemes that shall be considered by the engine.
- *
- * @param maxPhonemes
- * the maximum number of phonemes returned by the engine
- * @since 1.7
- */
- public void setMaxPhonemes(final int maxPhonemes) {
- this.engine = new PhoneticEngine(this.engine.getNameType(),
- this.engine.getRuleType(),
- this.engine.isConcat(),
- maxPhonemes);
- }
-
}
diff --git a/src/main/java/org/apache/commons/codec/language/bm/Lang.java b/src/main/java/org/apache/commons/codec/language/bm/Lang.java
index 05bb751a..734f668d 100644
--- a/src/main/java/org/apache/commons/codec/language/bm/Lang.java
+++ b/src/main/java/org/apache/commons/codec/language/bm/Lang.java
@@ -83,14 +83,6 @@ public class Lang {
// guessing rules, perhaps by marking it protected and allowing sub-classing. However, the vast majority of users
// should be strongly encouraged to use the static factory {@code instance} method to get their Lang instances.
- private static final Map<NameType, Lang> LANGS = new EnumMap<>(NameType.class);
-
- private static final String LANGUAGE_RULES_RN = "org/apache/commons/codec/language/bm/%s_lang.txt";
-
- private final Languages languages;
-
- private final List<LangRule> rules;
-
private static final class LangRule {
private final boolean acceptOnMatch;
private final Set<String> languages;
@@ -107,6 +99,10 @@ public class Lang {
}
}
+ private static final Map<NameType, Lang> LANGS = new EnumMap<>(NameType.class);
+
+ private static final String LANGUAGE_RULES_RN = "org/apache/commons/codec/language/bm/%s_lang.txt";
+
static {
for (final NameType s : NameType.values()) {
LANGS.put(s, loadFromResource(String.format(LANGUAGE_RULES_RN, s.getName()), Languages.getInstance(s)));
@@ -185,6 +181,10 @@ public class Lang {
return new Lang(rules, languages);
}
+ private final Languages languages;
+
+ private final List<LangRule> rules;
+
private Lang(final List<LangRule> rules, final Languages languages) {
this.rules = Collections.unmodifiableList(rules);
this.languages = languages;
diff --git a/src/main/java/org/apache/commons/codec/language/bm/Languages.java b/src/main/java/org/apache/commons/codec/language/bm/Languages.java
index a06d44cf..c0f366f4 100644
--- a/src/main/java/org/apache/commons/codec/language/bm/Languages.java
+++ b/src/main/java/org/apache/commons/codec/language/bm/Languages.java
@@ -65,67 +65,116 @@ public class Languages {
// languages, and a second part that provides instance methods for accessing
// this set for supported languages.
- public static final String ANY = "any";
+ /**
+ * A set of languages.
+ */
+ public static abstract class LanguageSet {
- private static final Map<NameType, Languages> LANGUAGES = new EnumMap<>(NameType.class);
+ public static LanguageSet from(final Set<String> langs) {
+ return langs.isEmpty() ? NO_LANGUAGES : new SomeLanguages(langs);
+ }
+
+ public abstract boolean contains(String language);
+
+ public abstract String getAny();
+
+ public abstract boolean isEmpty();
+
+ public abstract boolean isSingleton();
+
+ abstract LanguageSet merge(LanguageSet other);
+
+ public abstract LanguageSet restrictTo(LanguageSet other);
+ }
/**
- * No languages at all.
+ * Some languages, explicitly enumerated.
*/
- public static final LanguageSet NO_LANGUAGES = new LanguageSet() {
+ public static final class SomeLanguages extends LanguageSet {
+ private final Set<String> languages;
+
+ private SomeLanguages(final Set<String> languages) {
+ this.languages = Collections.unmodifiableSet(languages);
+ }
+
@Override
public boolean contains(final String language) {
- return false;
+ return this.languages.contains(language);
}
@Override
public String getAny() {
- throw new NoSuchElementException("Can't fetch any language from the empty language set.");
+ return this.languages.iterator().next();
+ }
+
+ public Set<String> getLanguages() {
+ return this.languages;
}
@Override
public boolean isEmpty() {
- return true;
+ return this.languages.isEmpty();
}
@Override
public boolean isSingleton() {
- return false;
+ return this.languages.size() == 1;
}
@Override
- public LanguageSet restrictTo(final LanguageSet other) {
- return this;
+ public LanguageSet merge(final LanguageSet other) {
+ if (other == NO_LANGUAGES) {
+ return this;
+ }
+ if (other == ANY_LANGUAGE) {
+ return other;
+ }
+ final SomeLanguages someLanguages = (SomeLanguages) other;
+ final Set<String> set = new HashSet<>(languages);
+ set.addAll(someLanguages.languages);
+ return from(set);
}
@Override
- public LanguageSet merge(final LanguageSet other) {
- return other;
+ public LanguageSet restrictTo(final LanguageSet other) {
+ if (other == NO_LANGUAGES) {
+ return other;
+ }
+ if (other == ANY_LANGUAGE) {
+ return this;
+ }
+ final SomeLanguages someLanguages = (SomeLanguages) other;
+ return from(languages.stream().filter(lang -> someLanguages.languages.contains(lang)).collect(Collectors.toSet()));
}
@Override
public String toString() {
- return "NO_LANGUAGES";
+ return "Languages(" + languages.toString() + ")";
}
- };
+
+ }
+
+ public static final String ANY = "any";
+
+ private static final Map<NameType, Languages> LANGUAGES = new EnumMap<>(NameType.class);
/**
- * Any/all languages.
+ * No languages at all.
*/
- public static final LanguageSet ANY_LANGUAGE = new LanguageSet() {
+ public static final LanguageSet NO_LANGUAGES = new LanguageSet() {
@Override
public boolean contains(final String language) {
- return true;
+ return false;
}
@Override
public String getAny() {
- throw new NoSuchElementException("Can't fetch any language from the any language set.");
+ throw new NoSuchElementException("Can't fetch any language from the empty language set.");
}
@Override
public boolean isEmpty() {
- return false;
+ return true;
}
@Override
@@ -134,111 +183,60 @@ public class Languages {
}
@Override
- public LanguageSet restrictTo(final LanguageSet other) {
+ public LanguageSet merge(final LanguageSet other) {
return other;
}
@Override
- public LanguageSet merge(final LanguageSet other) {
- return other;
+ public LanguageSet restrictTo(final LanguageSet other) {
+ return this;
}
@Override
public String toString() {
- return "ANY_LANGUAGE";
+ return "NO_LANGUAGES";
}
};
- private final Set<String> languages;
-
/**
- * A set of languages.
- */
- public static abstract class LanguageSet {
-
- public static LanguageSet from(final Set<String> langs) {
- return langs.isEmpty() ? NO_LANGUAGES : new SomeLanguages(langs);
- }
-
- public abstract boolean contains(String language);
-
- public abstract String getAny();
-
- public abstract boolean isEmpty();
-
- public abstract boolean isSingleton();
-
- public abstract LanguageSet restrictTo(LanguageSet other);
-
- abstract LanguageSet merge(LanguageSet other);
- }
-
- /**
- * Some languages, explicitly enumerated.
+ * Any/all languages.
*/
- public static final class SomeLanguages extends LanguageSet {
- private final Set<String> languages;
-
- private SomeLanguages(final Set<String> languages) {
- this.languages = Collections.unmodifiableSet(languages);
- }
-
+ public static final LanguageSet ANY_LANGUAGE = new LanguageSet() {
@Override
public boolean contains(final String language) {
- return this.languages.contains(language);
+ return true;
}
@Override
public String getAny() {
- return this.languages.iterator().next();
- }
-
- public Set<String> getLanguages() {
- return this.languages;
+ throw new NoSuchElementException("Can't fetch any language from the any language set.");
}
@Override
public boolean isEmpty() {
- return this.languages.isEmpty();
+ return false;
}
@Override
public boolean isSingleton() {
- return this.languages.size() == 1;
+ return false;
}
@Override
- public LanguageSet restrictTo(final LanguageSet other) {
- if (other == NO_LANGUAGES) {
- return other;
- }
- if (other == ANY_LANGUAGE) {
- return this;
- }
- final SomeLanguages someLanguages = (SomeLanguages) other;
- return from(languages.stream().filter(lang -> someLanguages.languages.contains(lang)).collect(Collectors.toSet()));
+ public LanguageSet merge(final LanguageSet other) {
+ return other;
}
@Override
- public LanguageSet merge(final LanguageSet other) {
- if (other == NO_LANGUAGES) {
- return this;
- }
- if (other == ANY_LANGUAGE) {
- return other;
- }
- final SomeLanguages someLanguages = (SomeLanguages) other;
- final Set<String> set = new HashSet<>(languages);
- set.addAll(someLanguages.languages);
- return from(set);
+ public LanguageSet restrictTo(final LanguageSet other) {
+ return other;
}
@Override
public String toString() {
- return "Languages(" + languages.toString() + ")";
+ return "ANY_LANGUAGE";
}
-
- }
+ };
static {
for (final NameType s : NameType.values()) {
@@ -276,6 +274,8 @@ public class Languages {
return String.format("org/apache/commons/codec/language/bm/%s_languages.txt", nameType.getName());
}
+ private final Set<String> languages;
+
private Languages(final Set<String> languages) {
this.languages = languages;
}
diff --git a/src/main/java/org/apache/commons/codec/language/bm/PhoneticEngine.java b/src/main/java/org/apache/commons/codec/language/bm/PhoneticEngine.java
index 85fa753a..ef69a2a4 100644
--- a/src/main/java/org/apache/commons/codec/language/bm/PhoneticEngine.java
+++ b/src/main/java/org/apache/commons/codec/language/bm/PhoneticEngine.java
@@ -55,34 +55,6 @@ import org.apache.commons.codec.language.bm.Rule.Phoneme;
*/
public class PhoneticEngine {
- private static final int DEFAULT_MAX_PHONEMES = 20;
-
- private static final Map<NameType, Set<String>> NAME_PREFIXES = new EnumMap<>(NameType.class);
-
- private final Lang lang;
-
- private final NameType nameType;
-
- private final RuleType ruleType;
-
- private final boolean concat;
-
- private final int maxPhonemes;
-
- static {
- NAME_PREFIXES.put(NameType.ASHKENAZI,
- Collections.unmodifiableSet(
- new HashSet<>(Arrays.asList("bar", "ben", "da", "de", "van", "von"))));
- NAME_PREFIXES.put(NameType.SEPHARDIC,
- Collections.unmodifiableSet(
- new HashSet<>(Arrays.asList("al", "el", "da", "dal", "de", "del", "dela", "de la",
- "della", "des", "di", "do", "dos", "du", "van", "von"))));
- NAME_PREFIXES.put(NameType.GENERIC,
- Collections.unmodifiableSet(
- new HashSet<>(Arrays.asList("da", "dal", "de", "del", "dela", "de la", "della",
- "des", "di", "do", "dos", "du", "van", "von"))));
- }
-
/**
* Utility for manipulating a set of phonemes as they are being built up. Not intended for use outside
* this package, and probably not outside the {@link PhoneticEngine} class.
@@ -91,8 +63,6 @@ public class PhoneticEngine {
*/
static final class PhonemeBuilder {
- private final Set<Rule.Phoneme> phonemes;
-
/**
* An empty builder where all phonemes must come from some set of languages. This will contain a single
* phoneme of zero characters. This can then be appended to. This should be the only way to create a new
@@ -105,6 +75,8 @@ public class PhoneticEngine {
return new PhonemeBuilder(new Rule.Phoneme("", languages));
}
+ private final Set<Rule.Phoneme> phonemes;
+
private PhonemeBuilder(final Rule.Phoneme phoneme) {
this.phonemes = new LinkedHashSet<>();
this.phonemes.add(phoneme);
@@ -251,6 +223,24 @@ public class PhoneticEngine {
}
}
+ private static final int DEFAULT_MAX_PHONEMES = 20;
+
+ private static final Map<NameType, Set<String>> NAME_PREFIXES = new EnumMap<>(NameType.class);
+
+ static {
+ NAME_PREFIXES.put(NameType.ASHKENAZI,
+ Collections.unmodifiableSet(
+ new HashSet<>(Arrays.asList("bar", "ben", "da", "de", "van", "von"))));
+ NAME_PREFIXES.put(NameType.SEPHARDIC,
+ Collections.unmodifiableSet(
+ new HashSet<>(Arrays.asList("al", "el", "da", "dal", "de", "del", "dela", "de la",
+ "della", "des", "di", "do", "dos", "du", "van", "von"))));
+ NAME_PREFIXES.put(NameType.GENERIC,
+ Collections.unmodifiableSet(
+ new HashSet<>(Arrays.asList("da", "dal", "de", "del", "dela", "de la", "della",
+ "des", "di", "do", "dos", "du", "van", "von"))));
+ }
+
/**
* Joins some strings with an internal separator.
*
@@ -262,6 +252,16 @@ public class PhoneticEngine {
return strings.stream().collect(Collectors.joining(sep));
}
+ private final Lang lang;
+
+ private final NameType nameType;
+
+ private final RuleType ruleType;
+
+ private final boolean concat;
+
+ private final int maxPhonemes;
+
/**
* Generates a new, fully-configured phonetic engine.
*
@@ -466,6 +466,16 @@ public class PhoneticEngine {
return this.lang;
}
+ /**
+ * Gets the maximum number of phonemes the engine will calculate for a given input.
+ *
+ * @return the maximum number of phonemes
+ * @since 1.7
+ */
+ public int getMaxPhonemes() {
+ return this.maxPhonemes;
+ }
+
/**
* Gets the NameType being used.
*
@@ -492,14 +502,4 @@ public class PhoneticEngine {
public boolean isConcat() {
return this.concat;
}
-
- /**
- * Gets the maximum number of phonemes the engine will calculate for a given input.
- *
- * @return the maximum number of phonemes
- * @since 1.7
- */
- public int getMaxPhonemes() {
- return this.maxPhonemes;
- }
}
diff --git a/src/main/java/org/apache/commons/codec/language/bm/Rule.java b/src/main/java/org/apache/commons/codec/language/bm/Rule.java
index 620195d7..028a22f4 100644
--- a/src/main/java/org/apache/commons/codec/language/bm/Rule.java
+++ b/src/main/java/org/apache/commons/codec/language/bm/Rule.java
@@ -84,32 +84,8 @@ import org.apache.commons.codec.language.bm.Languages.LanguageSet;
*/
public class Rule {
- public static final RPattern ALL_STRINGS_RMATCHER = input -> true;
-
- public static final String ALL = "ALL";
-
- private static final String DOUBLE_QUOTE = "\"";
-
- private static final String HASH_INCLUDE = "#include";
-
- private static final int HASH_INCLUDE_LENGTH = HASH_INCLUDE.length();
-
- private static final Map<NameType, Map<RuleType, Map<String, Map<String, List<Rule>>>>> RULES =
- new EnumMap<>(NameType.class);
-
- private final RPattern lContext;
-
- private final String pattern;
-
- private final PhonemeExpr phoneme;
-
- private final RPattern rContext;
-
public static final class Phoneme implements PhonemeExpr {
- private final StringBuilder phonemeText;
- private final Languages.LanguageSet languages;
-
public static final Comparator<Phoneme> COMPARATOR = (o1, o2) -> {
final int o1Length = o1.phonemeText.length();
final int o2Length = o2.phonemeText.length();
@@ -129,6 +105,9 @@ public class Rule {
return 0;
};
+ private final StringBuilder phonemeText;
+
+ private final Languages.LanguageSet languages;
public Phoneme(final CharSequence phonemeText, final Languages.LanguageSet languages) {
this.phonemeText = new StringBuilder(phonemeText);
@@ -218,6 +197,19 @@ public class Rule {
boolean isMatch(CharSequence input);
}
+ public static final RPattern ALL_STRINGS_RMATCHER = input -> true;
+
+ public static final String ALL = "ALL";
+
+ private static final String DOUBLE_QUOTE = "\"";
+
+ private static final String HASH_INCLUDE = "#include";
+
+ private static final int HASH_INCLUDE_LENGTH = HASH_INCLUDE.length();
+
+ private static final Map<NameType, Map<RuleType, Map<String, Map<String, List<Rule>>>>> RULES =
+ new EnumMap<>(NameType.class);
+
static {
for (final NameType s : NameType.values()) {
final Map<RuleType, Map<String, Map<String, List<Rule>>>> rts =
@@ -579,6 +571,14 @@ public class Rule {
return str;
}
+ private final RPattern lContext;
+
+ private final String pattern;
+
+ private final PhonemeExpr phoneme;
+
+ private final RPattern rContext;
+
/**
* Creates a new rule.
*
diff --git a/src/main/java/org/apache/commons/codec/net/BCodec.java b/src/main/java/org/apache/commons/codec/net/BCodec.java
index 943f2ea8..481cd1e0 100644
--- a/src/main/java/org/apache/commons/codec/net/BCodec.java
+++ b/src/main/java/org/apache/commons/codec/net/BCodec.java
@@ -114,30 +114,49 @@ public class BCodec extends RFC1522Codec implements StringEncoder, StringDecoder
}
/**
- * Returns true if decoding behavior is strict. Decoding will raise a
- * {@link DecoderException} if trailing bits are not part of a valid Base64 encoding.
- *
- * <p>The default is false for lenient encoding. Decoding will compose trailing bits
- * into 8-bit bytes and discard the remainder.
+ * Decodes a Base64 object into its original form. Escaped characters are converted back to their original
+ * representation.
*
- * @return true if using strict decoding
- * @since 1.15
+ * @param value
+ * Base64 object to convert into its original form
+ * @return original object
+ * @throws DecoderException
+ * Thrown if the argument is not a {@code String}. Thrown if a failure condition is encountered
+ * during the decode process.
*/
- public boolean isStrictDecoding() {
- return decodingPolicy == CodecPolicy.STRICT;
- }
-
@Override
- protected String getEncoding() {
- return "B";
+ public Object decode(final Object value) throws DecoderException {
+ if (value == null) {
+ return null;
+ }
+ if (value instanceof String) {
+ return decode((String) value);
+ }
+ throw new DecoderException("Objects of type " +
+ value.getClass().getName() +
+ " cannot be decoded using BCodec");
}
+ /**
+ * Decodes a Base64 string into its original form. Escaped characters are converted back to their original
+ * representation.
+ *
+ * @param value
+ * Base64 string to convert into its original form
+ * @return original string
+ * @throws DecoderException
+ * A decoder exception is thrown if a failure condition is encountered during the decode process.
+ */
@Override
- protected byte[] doEncoding(final byte[] bytes) {
- if (bytes == null) {
+ public String decode(final String value) throws DecoderException {
+ if (value == null) {
return null;
}
- return Base64.encodeBase64(bytes);
+ try {
+ return this.decodeText(value);
+ } catch (final UnsupportedEncodingException | IllegalArgumentException e) {
+ throw new DecoderException(e.getMessage(), e);
+ }
}
@Override
@@ -148,45 +167,34 @@ public class BCodec extends RFC1522Codec implements StringEncoder, StringDecoder
return new Base64(0, BaseNCodec.getChunkSeparator(), false, decodingPolicy).decode(bytes);
}
- /**
- * Encodes a string into its Base64 form using the specified Charset. Unsafe characters are escaped.
- *
- * @param strSource
- * string to convert to Base64 form
- * @param sourceCharset
- * the Charset for {@code value}
- * @return Base64 string
- * @throws EncoderException
- * thrown if a failure condition is encountered during the encoding process.
- * @since 1.7
- */
- public String encode(final String strSource, final Charset sourceCharset) throws EncoderException {
- if (strSource == null) {
+ @Override
+ protected byte[] doEncoding(final byte[] bytes) {
+ if (bytes == null) {
return null;
}
- return encodeText(strSource, sourceCharset);
+ return Base64.encodeBase64(bytes);
}
/**
- * Encodes a string into its Base64 form using the specified Charset. Unsafe characters are escaped.
+ * Encodes an object into its Base64 form using the default Charset. Unsafe characters are escaped.
*
- * @param strSource
- * string to convert to Base64 form
- * @param sourceCharset
- * the Charset for {@code value}
- * @return Base64 string
+ * @param value
+ * object to convert to Base64 form
+ * @return Base64 object
* @throws EncoderException
* thrown if a failure condition is encountered during the encoding process.
*/
- public String encode(final String strSource, final String sourceCharset) throws EncoderException {
- if (strSource == null) {
+ @Override
+ public Object encode(final Object value) throws EncoderException {
+ if (value == null) {
return null;
}
- try {
- return this.encodeText(strSource, sourceCharset);
- } catch (final UnsupportedEncodingException e) {
- throw new EncoderException(e.getMessage(), e);
+ if (value instanceof String) {
+ return encode((String) value);
}
+ throw new EncoderException("Objects of type " +
+ value.getClass().getName() +
+ " cannot be encoded using BCodec");
}
/**
@@ -207,71 +215,44 @@ public class BCodec extends RFC1522Codec implements StringEncoder, StringDecoder
}
/**
- * Decodes a Base64 string into its original form. Escaped characters are converted back to their original
- * representation.
- *
- * @param value
- * Base64 string to convert into its original form
- * @return original string
- * @throws DecoderException
- * A decoder exception is thrown if a failure condition is encountered during the decode process.
- */
- @Override
- public String decode(final String value) throws DecoderException {
- if (value == null) {
- return null;
- }
- try {
- return this.decodeText(value);
- } catch (final UnsupportedEncodingException | IllegalArgumentException e) {
- throw new DecoderException(e.getMessage(), e);
- }
- }
-
- /**
- * Encodes an object into its Base64 form using the default Charset. Unsafe characters are escaped.
+ * Encodes a string into its Base64 form using the specified Charset. Unsafe characters are escaped.
*
- * @param value
- * object to convert to Base64 form
- * @return Base64 object
+ * @param strSource
+ * string to convert to Base64 form
+ * @param sourceCharset
+ * the Charset for {@code value}
+ * @return Base64 string
* @throws EncoderException
* thrown if a failure condition is encountered during the encoding process.
+ * @since 1.7
*/
- @Override
- public Object encode(final Object value) throws EncoderException {
- if (value == null) {
+ public String encode(final String strSource, final Charset sourceCharset) throws EncoderException {
+ if (strSource == null) {
return null;
}
- if (value instanceof String) {
- return encode((String) value);
- }
- throw new EncoderException("Objects of type " +
- value.getClass().getName() +
- " cannot be encoded using BCodec");
+ return encodeText(strSource, sourceCharset);
}
/**
- * Decodes a Base64 object into its original form. Escaped characters are converted back to their original
- * representation.
+ * Encodes a string into its Base64 form using the specified Charset. Unsafe characters are escaped.
*
- * @param value
- * Base64 object to convert into its original form
- * @return original object
- * @throws DecoderException
- * Thrown if the argument is not a {@code String}. Thrown if a failure condition is encountered
- * during the decode process.
+ * @param strSource
+ * string to convert to Base64 form
+ * @param sourceCharset
+ * the Charset for {@code value}
+ * @return Base64 string
+ * @throws EncoderException
+ * thrown if a failure condition is encountered during the encoding process.
*/
- @Override
- public Object decode(final Object value) throws DecoderException {
- if (value == null) {
+ public String encode(final String strSource, final String sourceCharset) throws EncoderException {
+ if (strSource == null) {
return null;
}
- if (value instanceof String) {
- return decode((String) value);
+ try {
+ return this.encodeText(strSource, sourceCharset);
+ } catch (final UnsupportedEncodingException e) {
+ throw new EncoderException(e.getMessage(), e);
}
- throw new DecoderException("Objects of type " +
- value.getClass().getName() +
- " cannot be decoded using BCodec");
}
/**
@@ -292,4 +273,23 @@ public class BCodec extends RFC1522Codec implements StringEncoder, StringDecoder
public String getDefaultCharset() {
return this.charset.name();
}
+
+ @Override
+ protected String getEncoding() {
+ return "B";
+ }
+
+ /**
+ * Returns true if decoding behavior is strict. Decoding will raise a
+ * {@link DecoderException} if trailing bits are not part of a valid Base64 encoding.
+ *
+ * <p>The default is false for lenient encoding. Decoding will compose trailing bits
+ * into 8-bit bytes and discard the remainder.
+ *
+ * @return true if using strict decoding
+ * @since 1.15
+ */
+ public boolean isStrictDecoding() {
+ return decodingPolicy == CodecPolicy.STRICT;
+ }
}
diff --git a/src/main/java/org/apache/commons/codec/net/PercentCodec.java b/src/main/java/org/apache/commons/codec/net/PercentCodec.java
index 31288642..8e515381 100644
--- a/src/main/java/org/apache/commons/codec/net/PercentCodec.java
+++ b/src/main/java/org/apache/commons/codec/net/PercentCodec.java
@@ -83,52 +83,65 @@ public class PercentCodec implements BinaryEncoder, BinaryDecoder {
insertAlwaysEncodeChars(alwaysEncodeChars);
}
- /**
- * Adds the byte array into a BitSet for faster lookup
- *
- * @param alwaysEncodeCharsArray
- */
- private void insertAlwaysEncodeChars(final byte[] alwaysEncodeCharsArray) {
- if (alwaysEncodeCharsArray != null) {
- for (final byte b : alwaysEncodeCharsArray) {
- insertAlwaysEncodeChar(b);
+ private boolean canEncode(final byte c) {
+ return !isAsciiChar(c) || inAlwaysEncodeCharsRange(c) && alwaysEncodeChars.get(c);
+ }
+
+ private boolean containsSpace(final byte[] bytes) {
+ for (final byte b : bytes) {
+ if (b == ' ') {
+ return true;
}
}
- insertAlwaysEncodeChar(ESCAPE_CHAR);
+ return false;
}
/**
- * Inserts a single character into a BitSet and maintains the min and max of the characters of the
- * {@code BitSet alwaysEncodeChars} in order to avoid look-ups when a byte is out of this range.
- *
- * @param b the byte that is candidate for min and max limit
+ * Decode bytes encoded with Percent-Encoding based on RFC 3986. The reverse process is performed in order to
+ * decode the encoded characters to Unicode.
*/
- private void insertAlwaysEncodeChar(final byte b) {
- this.alwaysEncodeChars.set(b);
- if (b < alwaysEncodeCharsMin) {
- alwaysEncodeCharsMin = b;
+ @Override
+ public byte[] decode(final byte[] bytes) throws DecoderException {
+ if (bytes == null) {
+ return null;
}
- if (b > alwaysEncodeCharsMax) {
- alwaysEncodeCharsMax = b;
+
+ final ByteBuffer buffer = ByteBuffer.allocate(expectedDecodingBytes(bytes));
+ for (int i = 0; i < bytes.length; i++) {
+ final byte b = bytes[i];
+ if (b == ESCAPE_CHAR) {
+ try {
+ final int u = Utils.digit16(bytes[++i]);
+ final int l = Utils.digit16(bytes[++i]);
+ buffer.put((byte) ((u << 4) + l));
+ } catch (final ArrayIndexOutOfBoundsException e) {
+ throw new DecoderException("Invalid percent decoding: ", e);
+ }
+ } else if (plusForSpace && b == '+') {
+ buffer.put((byte) ' ');
+ } else {
+ buffer.put(b);
+ }
}
+ return buffer.array();
}
/**
- * Percent-Encoding based on RFC 3986. The non US-ASCII characters are encoded, as well as the
- * US-ASCII characters that are configured to be always encoded.
+ * Decodes a byte[] Object, whose bytes are encoded with Percent-Encoding.
+ *
+ * @param obj the object to decode
+ * @return the decoding result byte[] as Object
+ * @throws DecoderException if the object is not a byte array
*/
@Override
- public byte[] encode(final byte[] bytes) throws EncoderException {
- if (bytes == null) {
+ public Object decode(final Object obj) throws DecoderException {
+ if (obj == null) {
return null;
}
-
- final int expectedEncodingBytes = expectedEncodingBytes(bytes);
- final boolean willEncode = expectedEncodingBytes != bytes.length;
- if (willEncode || plusForSpace && containsSpace(bytes)) {
- return doEncode(bytes, expectedEncodingBytes, willEncode);
+ if (obj instanceof byte[]) {
+ return decode((byte[]) obj);
}
- return bytes;
+ throw new DecoderException("Objects of type " + obj.getClass().getName() + " cannot be Percent decoded");
}
private byte[] doEncode(final byte[] bytes, final int expectedLength, final boolean willEncode) {
@@ -153,63 +166,40 @@ public class PercentCodec implements BinaryEncoder, BinaryDecoder {
return buffer.array();
}
- private int expectedEncodingBytes(final byte[] bytes) {
- int byteCount = 0;
- for (final byte b : bytes) {
- byteCount += canEncode(b) ? 3: 1;
+ /**
+ * Percent-Encoding based on RFC 3986. The non US-ASCII characters are encoded, as well as the
+ * US-ASCII characters that are configured to be always encoded.
+ */
+ @Override
+ public byte[] encode(final byte[] bytes) throws EncoderException {
+ if (bytes == null) {
+ return null;
}
- return byteCount;
- }
- private boolean containsSpace(final byte[] bytes) {
- for (final byte b : bytes) {
- if (b == ' ') {
- return true;
- }
+ final int expectedEncodingBytes = expectedEncodingBytes(bytes);
+ final boolean willEncode = expectedEncodingBytes != bytes.length;
+ if (willEncode || plusForSpace && containsSpace(bytes)) {
+ return doEncode(bytes, expectedEncodingBytes, willEncode);
}
- return false;
- }
-
- private boolean canEncode(final byte c) {
- return !isAsciiChar(c) || inAlwaysEncodeCharsRange(c) && alwaysEncodeChars.get(c);
- }
-
- private boolean inAlwaysEncodeCharsRange(final byte c) {
- return c >= alwaysEncodeCharsMin && c <= alwaysEncodeCharsMax;
- }
-
- private boolean isAsciiChar(final byte c) {
- return c >= 0;
+ return bytes;
}
/**
- * Decode bytes encoded with Percent-Encoding based on RFC 3986. The reverse process is performed in order to
- * decode the encoded characters to Unicode.
+ * Encodes an object into using the Percent-Encoding. Only byte[] objects are accepted.
+ *
+ * @param obj the object to encode
+ * @return the encoding result byte[] as Object
+ * @throws EncoderException if the object is not a byte array
*/
@Override
- public byte[] decode(final byte[] bytes) throws DecoderException {
- if (bytes == null) {
+ public Object encode(final Object obj) throws EncoderException {
+ if (obj == null) {
return null;
}
-
- final ByteBuffer buffer = ByteBuffer.allocate(expectedDecodingBytes(bytes));
- for (int i = 0; i < bytes.length; i++) {
- final byte b = bytes[i];
- if (b == ESCAPE_CHAR) {
- try {
- final int u = Utils.digit16(bytes[++i]);
- final int l = Utils.digit16(bytes[++i]);
- buffer.put((byte) ((u << 4) + l));
- } catch (final ArrayIndexOutOfBoundsException e) {
- throw new DecoderException("Invalid percent decoding: ", e);
- }
- } else if (plusForSpace && b == '+') {
- buffer.put((byte) ' ');
- } else {
- buffer.put(b);
- }
+ if (obj instanceof byte[]) {
+ return encode((byte[]) obj);
}
- return buffer.array();
+ throw new EncoderException("Objects of type " + obj.getClass().getName() + " cannot be Percent encoded");
}
private int expectedDecodingBytes(final byte[] bytes) {
@@ -222,39 +212,49 @@ public class PercentCodec implements BinaryEncoder, BinaryDecoder {
return byteCount;
}
+ private int expectedEncodingBytes(final byte[] bytes) {
+ int byteCount = 0;
+ for (final byte b : bytes) {
+ byteCount += canEncode(b) ? 3: 1;
+ }
+ return byteCount;
+ }
+
+ private boolean inAlwaysEncodeCharsRange(final byte c) {
+ return c >= alwaysEncodeCharsMin && c <= alwaysEncodeCharsMax;
+ }
+
/**
- * Encodes an object into using the Percent-Encoding. Only byte[] objects are accepted.
+ * Inserts a single character into a BitSet and maintains the min and max of the characters of the
+ * {@code BitSet alwaysEncodeChars} in order to avoid look-ups when a byte is out of this range.
*
- * @param obj the object to encode
- * @return the encoding result byte[] as Object
- * @throws EncoderException if the object is not a byte array
+ * @param b the byte that is candidate for min and max limit
*/
- @Override
- public Object encode(final Object obj) throws EncoderException {
- if (obj == null) {
- return null;
+ private void insertAlwaysEncodeChar(final byte b) {
+ this.alwaysEncodeChars.set(b);
+ if (b < alwaysEncodeCharsMin) {
+ alwaysEncodeCharsMin = b;
}
- if (obj instanceof byte[]) {
- return encode((byte[]) obj);
+ if (b > alwaysEncodeCharsMax) {
+ alwaysEncodeCharsMax = b;
}
- throw new EncoderException("Objects of type " + obj.getClass().getName() + " cannot be Percent encoded");
}
/**
- * Decodes a byte[] Object, whose bytes are encoded with Percent-Encoding.
+ * Adds the byte array into a BitSet for faster lookup
*
- * @param obj the object to decode
- * @return the decoding result byte[] as Object
- * @throws DecoderException if the object is not a byte array
+ * @param alwaysEncodeCharsArray
*/
- @Override
- public Object decode(final Object obj) throws DecoderException {
- if (obj == null) {
- return null;
- }
- if (obj instanceof byte[]) {
- return decode((byte[]) obj);
+ private void insertAlwaysEncodeChars(final byte[] alwaysEncodeCharsArray) {
+ if (alwaysEncodeCharsArray != null) {
+ for (final byte b : alwaysEncodeCharsArray) {
+ insertAlwaysEncodeChar(b);
+ }
}
- throw new DecoderException("Objects of type " + obj.getClass().getName() + " cannot be Percent decoded");
+ insertAlwaysEncodeChar(ESCAPE_CHAR);
+ }
+
+ private boolean isAsciiChar(final byte c) {
+ return c >= 0;
}
}
diff --git a/src/main/java/org/apache/commons/codec/net/QCodec.java b/src/main/java/org/apache/commons/codec/net/QCodec.java
index 6717cf78..e5b4c215 100644
--- a/src/main/java/org/apache/commons/codec/net/QCodec.java
+++ b/src/main/java/org/apache/commons/codec/net/QCodec.java
@@ -51,15 +51,11 @@ import org.apache.commons.codec.StringEncoder;
* @since 1.3
*/
public class QCodec extends RFC1522Codec implements StringEncoder, StringDecoder {
- /**
- * The default Charset used for string decoding and encoding.
- */
- private final Charset charset;
-
/**
* BitSet of printable characters as defined in RFC 1522.
*/
private static final BitSet PRINTABLE_CHARS = new BitSet(256);
+
// Static initializer for printable chars collection
static {
// alpha characters
@@ -103,11 +99,15 @@ public class QCodec extends RFC1522Codec implements StringEncoder, StringDecoder
PRINTABLE_CHARS.set('}');
PRINTABLE_CHARS.set('~');
}
-
private static final byte SPACE = 32;
private static final byte UNDERSCORE = 95;
+ /**
+ * The default Charset used for string decoding and encoding.
+ */
+ private final Charset charset;
+
private boolean encodeBlanks = false;
/**
@@ -144,25 +144,50 @@ public class QCodec extends RFC1522Codec implements StringEncoder, StringDecoder
this(Charset.forName(charsetName));
}
+ /**
+ * Decodes a quoted-printable object into its original form. Escaped characters are converted back to their original
+ * representation.
+ *
+ * @param obj
+ * quoted-printable object to convert into its original form
+ * @return original object
+ * @throws DecoderException
+ * Thrown if the argument is not a {@code String}. Thrown if a failure condition is encountered
+ * during the decode process.
+ */
@Override
- protected String getEncoding() {
- return "Q";
+ public Object decode(final Object obj) throws DecoderException {
+ if (obj == null) {
+ return null;
+ }
+ if (obj instanceof String) {
+ return decode((String) obj);
+ }
+ throw new DecoderException("Objects of type " +
+ obj.getClass().getName() +
+ " cannot be decoded using Q codec");
}
+ /**
+ * Decodes a quoted-printable string into its original form. Escaped characters are converted back to their original
+ * representation.
+ *
+ * @param str
+ * quoted-printable string to convert into its original form
+ * @return original string
+ * @throws DecoderException
+ * A decoder exception is thrown if a failure condition is encountered during the decode process.
+ */
@Override
- protected byte[] doEncoding(final byte[] bytes) {
- if (bytes == null) {
+ public String decode(final String str) throws DecoderException {
+ if (str == null) {
return null;
}
- final byte[] data = QuotedPrintableCodec.encodeQuotedPrintable(PRINTABLE_CHARS, bytes);
- if (this.encodeBlanks) {
- for (int i = 0; i < data.length; i++) {
- if (data[i] == SPACE) {
- data[i] = UNDERSCORE;
- }
- }
+ try {
+ return decodeText(str);
+ } catch (final UnsupportedEncodingException e) {
+ throw new DecoderException(e.getMessage(), e);
}
- return data;
}
@Override
@@ -192,45 +217,42 @@ public class QCodec extends RFC1522Codec implements StringEncoder, StringDecoder
return QuotedPrintableCodec.decodeQuotedPrintable(bytes);
}
- /**
- * Encodes a string into its quoted-printable form using the specified Charset. Unsafe characters are escaped.
- *
- * @param sourceStr
- * string to convert to quoted-printable form
- * @param sourceCharset
- * the Charset for sourceStr
- * @return quoted-printable string
- * @throws EncoderException
- * thrown if a failure condition is encountered during the encoding process.
- * @since 1.7
- */
- public String encode(final String sourceStr, final Charset sourceCharset) throws EncoderException {
- if (sourceStr == null) {
+ @Override
+ protected byte[] doEncoding(final byte[] bytes) {
+ if (bytes == null) {
return null;
}
- return encodeText(sourceStr, sourceCharset);
+ final byte[] data = QuotedPrintableCodec.encodeQuotedPrintable(PRINTABLE_CHARS, bytes);
+ if (this.encodeBlanks) {
+ for (int i = 0; i < data.length; i++) {
+ if (data[i] == SPACE) {
+ data[i] = UNDERSCORE;
+ }
+ }
+ }
+ return data;
}
/**
- * Encodes a string into its quoted-printable form using the specified Charset. Unsafe characters are escaped.
+ * Encodes an object into its quoted-printable form using the default Charset. Unsafe characters are escaped.
*
- * @param sourceStr
- * string to convert to quoted-printable form
- * @param sourceCharset
- * the Charset for sourceStr
- * @return quoted-printable string
+ * @param obj
+ * object to convert to quoted-printable form
+ * @return quoted-printable object
* @throws EncoderException
* thrown if a failure condition is encountered during the encoding process.
*/
- public String encode(final String sourceStr, final String sourceCharset) throws EncoderException {
- if (sourceStr == null) {
+ @Override
+ public Object encode(final Object obj) throws EncoderException {
+ if (obj == null) {
return null;
}
- try {
- return encodeText(sourceStr, sourceCharset);
- } catch (final UnsupportedEncodingException e) {
- throw new EncoderException(e.getMessage(), e);
+ if (obj instanceof String) {
+ return encode((String) obj);
}
+ throw new EncoderException("Objects of type " +
+ obj.getClass().getName() +
+ " cannot be encoded using Q codec");
}
/**
@@ -251,71 +273,44 @@ public class QCodec extends RFC1522Codec implements StringEncoder, StringDecoder
}
/**
- * Decodes a quoted-printable string into its original form. Escaped characters are converted back to their original
- * representation.
- *
- * @param str
- * quoted-printable string to convert into its original form
- * @return original string
- * @throws DecoderException
- * A decoder exception is thrown if a failure condition is encountered during the decode process.
- */
- @Override
- public String decode(final String str) throws DecoderException {
- if (str == null) {
- return null;
- }
- try {
- return decodeText(str);
- } catch (final UnsupportedEncodingException e) {
- throw new DecoderException(e.getMessage(), e);
- }
- }
-
- /**
- * Encodes an object into its quoted-printable form using the default Charset. Unsafe characters are escaped.
+ * Encodes a string into its quoted-printable form using the specified Charset. Unsafe characters are escaped.
*
- * @param obj
- * object to convert to quoted-printable form
- * @return quoted-printable object
+ * @param sourceStr
+ * string to convert to quoted-printable form
+ * @param sourceCharset
+ * the Charset for sourceStr
+ * @return quoted-printable string
* @throws EncoderException
* thrown if a failure condition is encountered during the encoding process.
+ * @since 1.7
*/
- @Override
- public Object encode(final Object obj) throws EncoderException {
- if (obj == null) {
+ public String encode(final String sourceStr, final Charset sourceCharset) throws EncoderException {
+ if (sourceStr == null) {
return null;
}
- if (obj instanceof String) {
- return encode((String) obj);
- }
- throw new EncoderException("Objects of type " +
- obj.getClass().getName() +
- " cannot be encoded using Q codec");
+ return encodeText(sourceStr, sourceCharset);
}
/**
- * Decodes a quoted-printable object into its original form. Escaped characters are converted back to their original
- * representation.
+ * Encodes a string into its quoted-printable form using the specified Charset. Unsafe characters are escaped.
*
- * @param obj
- * quoted-printable object to convert into its original form
- * @return original object
- * @throws DecoderException
- * Thrown if the argument is not a {@code String}. Thrown if a failure condition is encountered
- * during the decode process.
+ * @param sourceStr
+ * string to convert to quoted-printable form
+ * @param sourceCharset
+ * the Charset for sourceStr
+ * @return quoted-printable string
+ * @throws EncoderException
+ * thrown if a failure condition is encountered during the encoding process.
*/
- @Override
- public Object decode(final Object obj) throws DecoderException {
- if (obj == null) {
+ public String encode(final String sourceStr, final String sourceCharset) throws EncoderException {
+ if (sourceStr == null) {
return null;
}
- if (obj instanceof String) {
- return decode((String) obj);
+ try {
+ return encodeText(sourceStr, sourceCharset);
+ } catch (final UnsupportedEncodingException e) {
+ throw new EncoderException(e.getMessage(), e);
}
- throw new DecoderException("Objects of type " +
- obj.getClass().getName() +
- " cannot be decoded using Q codec");
}
/**
@@ -337,6 +332,11 @@ public class QCodec extends RFC1522Codec implements StringEncoder, StringDecoder
return this.charset.name();
}
+ @Override
+ protected String getEncoding() {
+ return "Q";
+ }
+
/**
* Tests if optional transformation of SPACE characters is to be used
*
diff --git a/src/main/java/org/apache/commons/codec/net/QuotedPrintableCodec.java b/src/main/java/org/apache/commons/codec/net/QuotedPrintableCodec.java
index 51487161..b6eea3ec 100644
--- a/src/main/java/org/apache/commons/codec/net/QuotedPrintableCodec.java
+++ b/src/main/java/org/apache/commons/codec/net/QuotedPrintableCodec.java
@@ -69,16 +69,6 @@ import org.apache.commons.codec.binary.StringUtils;
* @since 1.3
*/
public class QuotedPrintableCodec implements BinaryEncoder, BinaryDecoder, StringEncoder, StringDecoder {
- /**
- * The default Charset used for string decoding and encoding.
- */
- private final Charset charset;
-
- /**
- * Indicates whether soft line breaks shall be used during encoding (rule #3-5).
- */
- private final boolean strict;
-
/**
* BitSet of printable characters as defined in RFC 1521.
*/
@@ -113,102 +103,44 @@ public class QuotedPrintableCodec implements BinaryEncoder, BinaryDecoder, Strin
}
/**
- * Default constructor, assumes default Charset of {@link StandardCharsets#UTF_8}
- */
- public QuotedPrintableCodec() {
- this(StandardCharsets.UTF_8, false);
- }
-
- /**
- * Constructor which allows for the selection of the strict mode.
- *
- * @param strict
- * if {@code true}, soft line breaks will be used
- * @since 1.10
- */
- public QuotedPrintableCodec(final boolean strict) {
- this(StandardCharsets.UTF_8, strict);
- }
-
- /**
- * Constructor which allows for the selection of a default Charset.
- *
- * @param charset
- * the default string Charset to use.
- * @since 1.7
- */
- public QuotedPrintableCodec(final Charset charset) {
- this(charset, false);
- }
-
- /**
- * Constructor which allows for the selection of a default Charset and strict mode.
- *
- * @param charset
- * the default string Charset to use.
- * @param strict
- * if {@code true}, soft line breaks will be used
- * @since 1.10
- */
- public QuotedPrintableCodec(final Charset charset, final boolean strict) {
- this.charset = charset;
- this.strict = strict;
- }
-
- /**
- * Constructor which allows for the selection of a default Charset.
- *
- * @param charsetName
- * the default string Charset to use.
- * @throws UnsupportedCharsetException
- * If no support for the named Charset is available
- * in this instance of the Java virtual machine
- * @throws IllegalArgumentException
- * If the given charsetName is null
- * @throws IllegalCharsetNameException
- * If the given Charset name is illegal
- *
- * @since 1.7 throws UnsupportedCharsetException if the named Charset is unavailable
- */
- public QuotedPrintableCodec(final String charsetName)
- throws IllegalCharsetNameException, IllegalArgumentException, UnsupportedCharsetException {
- this(Charset.forName(charsetName), false);
- }
-
- /**
- * Encodes byte into its quoted-printable representation.
- *
- * @param b
- * byte to encode
- * @param buffer
- * the buffer to write to
- * @return The number of bytes written to the {@code buffer}
- */
- private static final int encodeQuotedPrintable(final int b, final ByteArrayOutputStream buffer) {
- buffer.write(ESCAPE_CHAR);
- final char hex1 = Utils.hexDigit(b >> 4);
- final char hex2 = Utils.hexDigit(b);
- buffer.write(hex1);
- buffer.write(hex2);
- return 3;
- }
-
- /**
- * Return the byte at position {@code index} of the byte array and
- * make sure it is unsigned.
+ * Decodes an array quoted-printable characters into an array of original bytes. Escaped characters are converted
+ * back to their original representation.
+ * <p>
+ * This function fully implements the quoted-printable encoding specification (rule #1 through rule #5) as
+ * defined in RFC 1521.
+ * </p>
*
- * @param index
- * position in the array
* @param bytes
- * the byte array
- * @return the unsigned octet at position {@code index} from the array
+ * array of quoted-printable characters
+ * @return array of original bytes
+ * @throws DecoderException
+ * Thrown if quoted-printable decoding is unsuccessful
*/
- private static int getUnsignedOctet(final int index, final byte[] bytes) {
- int b = bytes[index];
- if (b < 0) {
- b = 256 + b;
+ public static final byte[] decodeQuotedPrintable(final byte[] bytes) throws DecoderException {
+ if (bytes == null) {
+ return null;
}
- return b;
+ final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ for (int i = 0; i < bytes.length; i++) {
+ final int b = bytes[i];
+ if (b == ESCAPE_CHAR) {
+ try {
+ // if the next octet is a CR we have found a soft line break
+ if (bytes[++i] == CR) {
+ continue;
+ }
+ final int u = Utils.digit16(bytes[i]);
+ final int l = Utils.digit16(bytes[++i]);
+ buffer.write((char) ((u << 4) + l));
+ } catch (final ArrayIndexOutOfBoundsException e) {
+ throw new DecoderException("Invalid quoted-printable encoding", e);
+ }
+ } else if (b != CR && b != LF) {
+ // every other octet is appended except for CR & LF
+ buffer.write(b);
+ }
+ }
+ return buffer.toByteArray();
}
/**
@@ -231,17 +163,6 @@ public class QuotedPrintableCodec implements BinaryEncoder, BinaryDecoder, Strin
return 1;
}
- /**
- * Checks whether the given byte is whitespace.
- *
- * @param b
- * byte to be checked
- * @return {@code true} if the byte is either a space or tab character
- */
- private static boolean isWhitespace(final int b) {
- return b == SPACE || b == TAB;
- }
-
/**
* Encodes an array of bytes into an array of quoted-printable 7-bit characters. Unsafe characters are escaped.
* <p>
@@ -344,61 +265,123 @@ public class QuotedPrintableCodec implements BinaryEncoder, BinaryDecoder, Strin
}
/**
- * Decodes an array quoted-printable characters into an array of original bytes. Escaped characters are converted
- * back to their original representation.
- * <p>
- * This function fully implements the quoted-printable encoding specification (rule #1 through rule #5) as
- * defined in RFC 1521.
- * </p>
+ * Encodes byte into its quoted-printable representation.
*
+ * @param b
+ * byte to encode
+ * @param buffer
+ * the buffer to write to
+ * @return The number of bytes written to the {@code buffer}
+ */
+ private static final int encodeQuotedPrintable(final int b, final ByteArrayOutputStream buffer) {
+ buffer.write(ESCAPE_CHAR);
+ final char hex1 = Utils.hexDigit(b >> 4);
+ final char hex2 = Utils.hexDigit(b);
+ buffer.write(hex1);
+ buffer.write(hex2);
+ return 3;
+ }
+
+ /**
+ * Return the byte at position {@code index} of the byte array and
+ * make sure it is unsigned.
+ *
+ * @param index
+ * position in the array
* @param bytes
- * array of quoted-printable characters
- * @return array of original bytes
- * @throws DecoderException
- * Thrown if quoted-printable decoding is unsuccessful
+ * the byte array
+ * @return the unsigned octet at position {@code index} from the array
*/
- public static final byte[] decodeQuotedPrintable(final byte[] bytes) throws DecoderException {
- if (bytes == null) {
- return null;
- }
- final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- for (int i = 0; i < bytes.length; i++) {
- final int b = bytes[i];
- if (b == ESCAPE_CHAR) {
- try {
- // if the next octet is a CR we have found a soft line break
- if (bytes[++i] == CR) {
- continue;
- }
- final int u = Utils.digit16(bytes[i]);
- final int l = Utils.digit16(bytes[++i]);
- buffer.write((char) ((u << 4) + l));
- } catch (final ArrayIndexOutOfBoundsException e) {
- throw new DecoderException("Invalid quoted-printable encoding", e);
- }
- } else if (b != CR && b != LF) {
- // every other octet is appended except for CR & LF
- buffer.write(b);
- }
+ private static int getUnsignedOctet(final int index, final byte[] bytes) {
+ int b = bytes[index];
+ if (b < 0) {
+ b = 256 + b;
}
- return buffer.toByteArray();
+ return b;
}
/**
- * Encodes an array of bytes into an array of quoted-printable 7-bit characters. Unsafe characters are escaped.
- * <p>
- * Depending on the selection of the {@code strict} parameter, this function either implements the full ruleset
- * or only a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in
- * RFC 1521 and is suitable for encoding binary data and unformatted text.
- * </p>
+ * Checks whether the given byte is whitespace.
*
- * @param bytes
- * array of bytes to be encoded
- * @return array of bytes containing quoted-printable data
+ * @param b
+ * byte to be checked
+ * @return {@code true} if the byte is either a space or tab character
*/
- @Override
- public byte[] encode(final byte[] bytes) {
- return encodeQuotedPrintable(PRINTABLE_CHARS, bytes, strict);
+ private static boolean isWhitespace(final int b) {
+ return b == SPACE || b == TAB;
+ }
+
+ /**
+ * The default Charset used for string decoding and encoding.
+ */
+ private final Charset charset;
+
+ /**
+ * Indicates whether soft line breaks shall be used during encoding (rule #3-5).
+ */
+ private final boolean strict;
+
+ /**
+ * Default constructor, assumes default Charset of {@link StandardCharsets#UTF_8}
+ */
+ public QuotedPrintableCodec() {
+ this(StandardCharsets.UTF_8, false);
+ }
+
+ /**
+ * Constructor which allows for the selection of the strict mode.
+ *
+ * @param strict
+ * if {@code true}, soft line breaks will be used
+ * @since 1.10
+ */
+ public QuotedPrintableCodec(final boolean strict) {
+ this(StandardCharsets.UTF_8, strict);
+ }
+
+ /**
+ * Constructor which allows for the selection of a default Charset.
+ *
+ * @param charset
+ * the default string Charset to use.
+ * @since 1.7
+ */
+ public QuotedPrintableCodec(final Charset charset) {
+ this(charset, false);
+ }
+
+ /**
+ * Constructor which allows for the selection of a default Charset and strict mode.
+ *
+ * @param charset
+ * the default string Charset to use.
+ * @param strict
+ * if {@code true}, soft line breaks will be used
+ * @since 1.10
+ */
+ public QuotedPrintableCodec(final Charset charset, final boolean strict) {
+ this.charset = charset;
+ this.strict = strict;
+ }
+
+ /**
+ * Constructor which allows for the selection of a default Charset.
+ *
+ * @param charsetName
+ * the default string Charset to use.
+ * @throws UnsupportedCharsetException
+ * If no support for the named Charset is available
+ * in this instance of the Java virtual machine
+ * @throws IllegalArgumentException
+ * If the given charsetName is null
+ * @throws IllegalCharsetNameException
+ * If the given Charset name is illegal
+ *
+ * @since 1.7 throws UnsupportedCharsetException if the named Charset is unavailable
+ */
+ public QuotedPrintableCodec(final String charsetName)
+ throws IllegalCharsetNameException, IllegalArgumentException, UnsupportedCharsetException {
+ this(Charset.forName(charsetName), false);
}
/**
@@ -421,24 +404,46 @@ public class QuotedPrintableCodec implements BinaryEncoder, BinaryDecoder, Strin
}
/**
- * Encodes a string into its quoted-printable form using the default string Charset. Unsafe characters are escaped.
- * <p>
- * Depending on the selection of the {@code strict} parameter, this function either implements the full ruleset
- * or only a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in
- * RFC 1521 and is suitable for encoding binary data and unformatted text.
- * </p>
+ * Decodes a quoted-printable object into its original form. Escaped characters are converted back to their original
+ * representation.
*
- * @param sourceStr
- * string to convert to quoted-printable form
- * @return quoted-printable string
- * @throws EncoderException
- * Thrown if quoted-printable encoding is unsuccessful
+ * @param obj
+ * quoted-printable object to convert into its original form
+ * @return original object
+ * @throws DecoderException
+ * Thrown if the argument is not a {@code String} or {@code byte[]}. Thrown if a failure
+ * condition is encountered during the decode process.
+ */
+ @Override
+ public Object decode(final Object obj) throws DecoderException {
+ if (obj == null) {
+ return null;
+ }
+ if (obj instanceof byte[]) {
+ return decode((byte[]) obj);
+ }
+ if (obj instanceof String) {
+ return decode((String) obj);
+ }
+ throw new DecoderException("Objects of type " +
+ obj.getClass().getName() +
+ " cannot be quoted-printable decoded");
+ }
+
+ /**
+ * Decodes a quoted-printable string into its original form using the default string Charset. Escaped characters are
+ * converted back to their original representation.
*
+ * @param sourceStr
+ * quoted-printable string to convert into its original form
+ * @return original string
+ * @throws DecoderException
+ * Thrown if quoted-printable decoding is unsuccessful. Thrown if Charset is not supported.
* @see #getCharset()
*/
@Override
- public String encode(final String sourceStr) throws EncoderException {
- return this.encode(sourceStr, getCharset());
+ public String decode(final String sourceStr) throws DecoderException {
+ return this.decode(sourceStr, this.getCharset());
}
/**
@@ -484,19 +489,20 @@ public class QuotedPrintableCodec implements BinaryEncoder, BinaryDecoder, Strin
}
/**
- * Decodes a quoted-printable string into its original form using the default string Charset. Escaped characters are
- * converted back to their original representation.
+ * Encodes an array of bytes into an array of quoted-printable 7-bit characters. Unsafe characters are escaped.
+ * <p>
+ * Depending on the selection of the {@code strict} parameter, this function either implements the full ruleset
+ * or only a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in
+ * RFC 1521 and is suitable for encoding binary data and unformatted text.
+ * </p>
*
- * @param sourceStr
- * quoted-printable string to convert into its original form
- * @return original string
- * @throws DecoderException
- * Thrown if quoted-printable decoding is unsuccessful. Thrown if Charset is not supported.
- * @see #getCharset()
+ * @param bytes
+ * array of bytes to be encoded
+ * @return array of bytes containing quoted-printable data
*/
@Override
- public String decode(final String sourceStr) throws DecoderException {
- return this.decode(sourceStr, this.getCharset());
+ public byte[] encode(final byte[] bytes) {
+ return encodeQuotedPrintable(PRINTABLE_CHARS, bytes, strict);
}
/**
@@ -526,49 +532,24 @@ public class QuotedPrintableCodec implements BinaryEncoder, BinaryDecoder, Strin
}
/**
- * Decodes a quoted-printable object into its original form. Escaped characters are converted back to their original
- * representation.
- *
- * @param obj
- * quoted-printable object to convert into its original form
- * @return original object
- * @throws DecoderException
- * Thrown if the argument is not a {@code String} or {@code byte[]}. Thrown if a failure
- * condition is encountered during the decode process.
- */
- @Override
- public Object decode(final Object obj) throws DecoderException {
- if (obj == null) {
- return null;
- }
- if (obj instanceof byte[]) {
- return decode((byte[]) obj);
- }
- if (obj instanceof String) {
- return decode((String) obj);
- }
- throw new DecoderException("Objects of type " +
- obj.getClass().getName() +
- " cannot be quoted-printable decoded");
- }
-
- /**
- * Gets the default Charset name used for string decoding and encoding.
+ * Encodes a string into its quoted-printable form using the default string Charset. Unsafe characters are escaped.
+ * <p>
+ * Depending on the selection of the {@code strict} parameter, this function either implements the full ruleset
+ * or only a subset of quoted-printable encoding specification (rule #1 and rule #2) as defined in
+ * RFC 1521 and is suitable for encoding binary data and unformatted text.
+ * </p>
*
- * @return the default Charset name
- * @since 1.7
- */
- public Charset getCharset() {
- return this.charset;
- }
-
- /**
- * Gets the default Charset name used for string decoding and encoding.
+ * @param sourceStr
+ * string to convert to quoted-printable form
+ * @return quoted-printable string
+ * @throws EncoderException
+ * Thrown if quoted-printable encoding is unsuccessful
*
- * @return the default Charset name
+ * @see #getCharset()
*/
- public String getDefaultCharset() {
- return this.charset.name();
+ @Override
+ public String encode(final String sourceStr) throws EncoderException {
+ return this.encode(sourceStr, getCharset());
}
/**
@@ -615,4 +596,23 @@ public class QuotedPrintableCodec implements BinaryEncoder, BinaryDecoder, Strin
}
return StringUtils.newStringUsAscii(encode(sourceStr.getBytes(sourceCharset)));
}
+
+ /**
+ * Gets the default Charset name used for string decoding and encoding.
+ *
+ * @return the default Charset name
+ * @since 1.7
+ */
+ public Charset getCharset() {
+ return this.charset;
+ }
+
+ /**
+ * Gets the default Charset name used for string decoding and encoding.
+ *
+ * @return the default Charset name
+ */
+ public String getDefaultCharset() {
+ return this.charset.name();
+ }
}
diff --git a/src/main/java/org/apache/commons/codec/net/RFC1522Codec.java b/src/main/java/org/apache/commons/codec/net/RFC1522Codec.java
index 2a16aa38..dfd77d1c 100644
--- a/src/main/java/org/apache/commons/codec/net/RFC1522Codec.java
+++ b/src/main/java/org/apache/commons/codec/net/RFC1522Codec.java
@@ -51,63 +51,6 @@ abstract class RFC1522Codec {
/** Postfix. */
protected static final String PREFIX = "=?";
- /**
- * Applies an RFC 1522 compliant encoding scheme to the given string of text with the given charset.
- * <p>
- * This method constructs the "encoded-word" header common to all the RFC 1522 codecs and then invokes
- * {@link #doEncoding(byte[])} method of a concrete class to perform the specific encoding.
- * </p>
- *
- * @param text
- * a string to encode
- * @param charset
- * a charset to be used
- * @return RFC 1522 compliant "encoded-word"
- * @throws EncoderException
- * thrown if there is an error condition during the Encoding process.
- * @see Charset
- */
- protected String encodeText(final String text, final Charset charset) throws EncoderException {
- if (text == null) {
- return null;
- }
- final StringBuilder buffer = new StringBuilder();
- buffer.append(PREFIX);
- buffer.append(charset);
- buffer.append(SEP);
- buffer.append(this.getEncoding());
- buffer.append(SEP);
- buffer.append(StringUtils.newStringUsAscii(this.doEncoding(text.getBytes(charset))));
- buffer.append(POSTFIX);
- return buffer.toString();
- }
-
- /**
- * Applies an RFC 1522 compliant encoding scheme to the given string of text with the given charset.
- * <p>
- * This method constructs the "encoded-word" header common to all the RFC 1522 codecs and then invokes
- * {@link #doEncoding(byte[])} method of a concrete class to perform the specific encoding.
- * </p>
- *
- * @param text
- * a string to encode
- * @param charsetName
- * the charset to use
- * @return RFC 1522 compliant "encoded-word"
- * @throws EncoderException
- * thrown if there is an error condition during the Encoding process.
- * @throws UnsupportedEncodingException
- * if charset is not available
- * @see Charset
- */
- protected String encodeText(final String text, final String charsetName)
- throws EncoderException, UnsupportedEncodingException {
- if (text == null) {
- return null;
- }
- return this.encodeText(text, Charset.forName(charsetName));
- }
-
/**
* Applies an RFC 1522 compliant decoding scheme to the given string of text.
* <p>
@@ -158,11 +101,15 @@ abstract class RFC1522Codec {
}
/**
- * Returns the codec name (referred to as encoding in the RFC 1522).
+ * Decodes an array of bytes using the defined encoding scheme.
*
- * @return name of the codec
+ * @param bytes
+ * Data to be decoded
+ * @return a byte array that contains decoded data
+ * @throws DecoderException
+ * A decoder exception is thrown if a Decoder encounters a failure condition during the decode process.
*/
- protected abstract String getEncoding();
+ protected abstract byte[] doDecoding(byte[] bytes) throws DecoderException;
/**
* Encodes an array of bytes using the defined encoding scheme.
@@ -176,13 +123,66 @@ abstract class RFC1522Codec {
protected abstract byte[] doEncoding(byte[] bytes) throws EncoderException;
/**
- * Decodes an array of bytes using the defined encoding scheme.
+ * Applies an RFC 1522 compliant encoding scheme to the given string of text with the given charset.
+ * <p>
+ * This method constructs the "encoded-word" header common to all the RFC 1522 codecs and then invokes
+ * {@link #doEncoding(byte[])} method of a concrete class to perform the specific encoding.
+ * </p>
*
- * @param bytes
- * Data to be decoded
- * @return a byte array that contains decoded data
- * @throws DecoderException
- * A decoder exception is thrown if a Decoder encounters a failure condition during the decode process.
+ * @param text
+ * a string to encode
+ * @param charset
+ * a charset to be used
+ * @return RFC 1522 compliant "encoded-word"
+ * @throws EncoderException
+ * thrown if there is an error condition during the Encoding process.
+ * @see Charset
*/
- protected abstract byte[] doDecoding(byte[] bytes) throws DecoderException;
+ protected String encodeText(final String text, final Charset charset) throws EncoderException {
+ if (text == null) {
+ return null;
+ }
+ final StringBuilder buffer = new StringBuilder();
+ buffer.append(PREFIX);
+ buffer.append(charset);
+ buffer.append(SEP);
+ buffer.append(this.getEncoding());
+ buffer.append(SEP);
+ buffer.append(StringUtils.newStringUsAscii(this.doEncoding(text.getBytes(charset))));
+ buffer.append(POSTFIX);
+ return buffer.toString();
+ }
+
+ /**
+ * Applies an RFC 1522 compliant encoding scheme to the given string of text with the given charset.
+ * <p>
+ * This method constructs the "encoded-word" header common to all the RFC 1522 codecs and then invokes
+ * {@link #doEncoding(byte[])} method of a concrete class to perform the specific encoding.
+ * </p>
+ *
+ * @param text
+ * a string to encode
+ * @param charsetName
+ * the charset to use
+ * @return RFC 1522 compliant "encoded-word"
+ * @throws EncoderException
+ * thrown if there is an error condition during the Encoding process.
+ * @throws UnsupportedEncodingException
+ * if charset is not available
+ * @see Charset
+ */
+ protected String encodeText(final String text, final String charsetName)
+ throws EncoderException, UnsupportedEncodingException {
+ if (text == null) {
+ return null;
+ }
+ return this.encodeText(text, Charset.forName(charsetName));
+ }
+
+ /**
+ * Returns the codec name (referred to as encoding in the RFC 1522).
+ *
+ * @return name of the codec
+ */
+ protected abstract String getEncoding();
}
diff --git a/src/main/java/org/apache/commons/codec/net/URLCodec.java b/src/main/java/org/apache/commons/codec/net/URLCodec.java
index d5809f3b..26ef3493 100644
--- a/src/main/java/org/apache/commons/codec/net/URLCodec.java
+++ b/src/main/java/org/apache/commons/codec/net/URLCodec.java
@@ -48,14 +48,6 @@ import org.apache.commons.codec.binary.StringUtils;
*/
public class URLCodec implements BinaryEncoder, BinaryDecoder, StringEncoder, StringDecoder {
- /**
- * The default charset used for string decoding and encoding.
- *
- * @deprecated TODO: This field will be changed to a private final Charset in 2.0. (CODEC-126)
- */
- @Deprecated
- protected volatile String charset; // added volatile: see CODEC-232
-
/**
* Release 1.5 made this field final.
*/
@@ -97,23 +89,41 @@ public class URLCodec implements BinaryEncoder, BinaryDecoder, StringEncoder, St
WWW_FORM_URL = (BitSet) WWW_FORM_URL_SAFE.clone();
}
-
- /**
- * Default constructor.
- */
- public URLCodec() {
- this(CharEncoding.UTF_8);
- }
-
/**
- * Constructor which allows for the selection of a default charset.
+ * Decodes an array of URL safe 7-bit characters into an array of original bytes. Escaped characters are converted
+ * back to their original representation.
*
- * @param charset the default string charset to use.
+ * @param bytes
+ * array of URL safe characters
+ * @return array of original bytes
+ * @throws DecoderException
+ * Thrown if URL decoding is unsuccessful
*/
- public URLCodec(final String charset) {
- this.charset = charset;
+ public static final byte[] decodeUrl(final byte[] bytes) throws DecoderException {
+ if (bytes == null) {
+ return null;
+ }
+ final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
+ for (int i = 0; i < bytes.length; i++) {
+ final int b = bytes[i];
+ if (b == '+') {
+ buffer.write(' ');
+ } else if (b == ESCAPE_CHAR) {
+ try {
+ final int u = Utils.digit16(bytes[++i]);
+ final int l = Utils.digit16(bytes[++i]);
+ buffer.write((char) ((u << 4) + l));
+ } catch (final ArrayIndexOutOfBoundsException e) {
+ throw new DecoderException("Invalid URL encoding: ", e);
+ }
+ } else {
+ buffer.write(b);
+ }
+ }
+ return buffer.toByteArray();
}
+
/**
* Encodes an array of bytes into an array of URL safe 7-bit characters. Unsafe characters are escaped.
*
@@ -154,52 +164,29 @@ public class URLCodec implements BinaryEncoder, BinaryDecoder, StringEncoder, St
}
/**
- * Decodes an array of URL safe 7-bit characters into an array of original bytes. Escaped characters are converted
- * back to their original representation.
+ * The default charset used for string decoding and encoding.
*
- * @param bytes
- * array of URL safe characters
- * @return array of original bytes
- * @throws DecoderException
- * Thrown if URL decoding is unsuccessful
+ * @deprecated TODO: This field will be changed to a private final Charset in 2.0. (CODEC-126)
*/
- public static final byte[] decodeUrl(final byte[] bytes) throws DecoderException {
- if (bytes == null) {
- return null;
- }
- final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
- for (int i = 0; i < bytes.length; i++) {
- final int b = bytes[i];
- if (b == '+') {
- buffer.write(' ');
- } else if (b == ESCAPE_CHAR) {
- try {
- final int u = Utils.digit16(bytes[++i]);
- final int l = Utils.digit16(bytes[++i]);
- buffer.write((char) ((u << 4) + l));
- } catch (final ArrayIndexOutOfBoundsException e) {
- throw new DecoderException("Invalid URL encoding: ", e);
- }
- } else {
- buffer.write(b);
- }
- }
- return buffer.toByteArray();
+ @Deprecated
+ protected volatile String charset; // added volatile: see CODEC-232
+
+ /**
+ * Default constructor.
+ */
+ public URLCodec() {
+ this(CharEncoding.UTF_8);
}
/**
- * Encodes an array of bytes into an array of URL safe 7-bit characters. Unsafe characters are escaped.
+ * Constructor which allows for the selection of a default charset.
*
- * @param bytes
- * array of bytes to convert to URL safe characters
- * @return array of bytes containing URL safe characters
+ * @param charset the default string charset to use.
*/
- @Override
- public byte[] encode(final byte[] bytes) {
- return encodeUrl(WWW_FORM_URL_SAFE, bytes);
+ public URLCodec(final String charset) {
+ this.charset = charset;
}
-
/**
* Decodes an array of URL safe 7-bit characters into an array of original bytes. Escaped characters are converted
* back to their original representation.
@@ -215,48 +202,55 @@ public class URLCodec implements BinaryEncoder, BinaryDecoder, StringEncoder, St
return decodeUrl(bytes);
}
+
/**
- * Encodes a string into its URL safe form using the specified string charset. Unsafe characters are escaped.
+ * Decodes a URL safe object into its original form. Escaped characters are converted back to their original
+ * representation.
*
- * @param str
- * string to convert to a URL safe form
- * @param charsetName
- * the charset for str
- * @return URL safe string
- * @throws UnsupportedEncodingException
- * Thrown if charset is not supported
+ * @param obj
+ * URL safe object to convert into its original form
+ * @return original object
+ * @throws DecoderException
+ * Thrown if the argument is not a {@code String} or {@code byte[]}. Thrown if a failure
+ * condition is encountered during the decode process.
*/
- public String encode(final String str, final String charsetName) throws UnsupportedEncodingException {
- if (str == null) {
+ @Override
+ public Object decode(final Object obj) throws DecoderException {
+ if (obj == null) {
return null;
}
- return StringUtils.newStringUsAscii(encode(str.getBytes(charsetName)));
+ if (obj instanceof byte[]) {
+ return decode((byte[]) obj);
+ }
+ if (obj instanceof String) {
+ return decode((String) obj);
+ }
+ throw new DecoderException("Objects of type " + obj.getClass().getName() + " cannot be URL decoded");
}
/**
- * Encodes a string into its URL safe form using the default string charset. Unsafe characters are escaped.
+ * Decodes a URL safe string into its original form using the default string charset. Escaped characters are
+ * converted back to their original representation.
*
* @param str
- * string to convert to a URL safe form
- * @return URL safe string
- * @throws EncoderException
- * Thrown if URL encoding is unsuccessful
- *
+ * URL safe string to convert into its original form
+ * @return original string
+ * @throws DecoderException
+ * Thrown if URL decoding is unsuccessful
* @see #getDefaultCharset()
*/
@Override
- public String encode(final String str) throws EncoderException {
+ public String decode(final String str) throws DecoderException {
if (str == null) {
return null;
}
try {
- return encode(str, getDefaultCharset());
+ return decode(str, getDefaultCharset());
} catch (final UnsupportedEncodingException e) {
- throw new EncoderException(e.getMessage(), e);
+ throw new DecoderException(e.getMessage(), e);
}
}
-
/**
* Decodes a URL safe string into its original form using the specified encoding. Escaped characters are converted
* back to their original representation.
@@ -279,27 +273,17 @@ public class URLCodec implements BinaryEncoder, BinaryDecoder, StringEncoder, St
return new String(decode(StringUtils.getBytesUsAscii(str)), charsetName);
}
+
/**
- * Decodes a URL safe string into its original form using the default string charset. Escaped characters are
- * converted back to their original representation.
+ * Encodes an array of bytes into an array of URL safe 7-bit characters. Unsafe characters are escaped.
*
- * @param str
- * URL safe string to convert into its original form
- * @return original string
- * @throws DecoderException
- * Thrown if URL decoding is unsuccessful
- * @see #getDefaultCharset()
+ * @param bytes
+ * array of bytes to convert to URL safe characters
+ * @return array of bytes containing URL safe characters
*/
@Override
- public String decode(final String str) throws DecoderException {
- if (str == null) {
- return null;
- }
- try {
- return decode(str, getDefaultCharset());
- } catch (final UnsupportedEncodingException e) {
- throw new DecoderException(e.getMessage(), e);
- }
+ public byte[] encode(final byte[] bytes) {
+ return encodeUrl(WWW_FORM_URL_SAFE, bytes);
}
/**
@@ -326,28 +310,44 @@ public class URLCodec implements BinaryEncoder, BinaryDecoder, StringEncoder, St
}
/**
- * Decodes a URL safe object into its original form. Escaped characters are converted back to their original
- * representation.
+ * Encodes a string into its URL safe form using the default string charset. Unsafe characters are escaped.
*
- * @param obj
- * URL safe object to convert into its original form
- * @return original object
- * @throws DecoderException
- * Thrown if the argument is not a {@code String} or {@code byte[]}. Thrown if a failure
- * condition is encountered during the decode process.
+ * @param str
+ * string to convert to a URL safe form
+ * @return URL safe string
+ * @throws EncoderException
+ * Thrown if URL encoding is unsuccessful
+ *
+ * @see #getDefaultCharset()
*/
@Override
- public Object decode(final Object obj) throws DecoderException {
- if (obj == null) {
+ public String encode(final String str) throws EncoderException {
+ if (str == null) {
return null;
}
- if (obj instanceof byte[]) {
- return decode((byte[]) obj);
+ try {
+ return encode(str, getDefaultCharset());
+ } catch (final UnsupportedEncodingException e) {
+ throw new EncoderException(e.getMessage(), e);
}
- if (obj instanceof String) {
- return decode((String) obj);
+ }
+
+ /**
+ * Encodes a string into its URL safe form using the specified string charset. Unsafe characters are escaped.
+ *
+ * @param str
+ * string to convert to a URL safe form
+ * @param charsetName
+ * the charset for str
+ * @return URL safe string
+ * @throws UnsupportedEncodingException
+ * Thrown if charset is not supported
+ */
+ public String encode(final String str, final String charsetName) throws UnsupportedEncodingException {
+ if (str == null) {
+ return null;
}
- throw new DecoderException("Objects of type " + obj.getClass().getName() + " cannot be URL decoded");
+ return StringUtils.newStringUsAscii(encode(str.getBytes(charsetName)));
}
/**
diff --git a/src/test/java/org/apache/commons/codec/CharsetsTest.java b/src/test/java/org/apache/commons/codec/CharsetsTest.java
index c2aa9edc..834413c4 100644
--- a/src/test/java/org/apache/commons/codec/CharsetsTest.java
+++ b/src/test/java/org/apache/commons/codec/CharsetsTest.java
@@ -29,6 +29,12 @@ import org.junit.jupiter.api.Test;
*/
public class CharsetsTest {
+ @SuppressWarnings("deprecation")
+ @Test
+ public void testIso8859_1() {
+ assertEquals("ISO-8859-1", Charsets.ISO_8859_1.name());
+ }
+
@Test
public void testToCharset() {
assertEquals(Charset.defaultCharset(), Charsets.toCharset((String) null));
@@ -37,12 +43,6 @@ public class CharsetsTest {
assertEquals(StandardCharsets.UTF_8, Charsets.toCharset(StandardCharsets.UTF_8));
}
- @SuppressWarnings("deprecation")
- @Test
- public void testIso8859_1() {
- assertEquals("ISO-8859-1", Charsets.ISO_8859_1.name());
- }
-
@SuppressWarnings("deprecation")
@Test
public void testUsAscii() {
diff --git a/src/test/java/org/apache/commons/codec/StringEncoderComparatorTest.java b/src/test/java/org/apache/commons/codec/StringEncoderComparatorTest.java
index b8495090..930aeb94 100644
--- a/src/test/java/org/apache/commons/codec/StringEncoderComparatorTest.java
+++ b/src/test/java/org/apache/commons/codec/StringEncoderComparatorTest.java
@@ -32,15 +32,6 @@ import org.junit.jupiter.api.Test;
*/
public class StringEncoderComparatorTest {
- @Test
- public void testComparatorWithSoundex() throws Exception {
- final StringEncoderComparator sCompare =
- new StringEncoderComparator( new Soundex() );
-
- assertEquals(0, sCompare.compare("O'Brien", "O'Brian"),
- "O'Brien and O'Brian didn't come out with the same Soundex, something must be wrong here");
- }
-
@SuppressWarnings("unchecked") // cannot easily avoid this warning
@Test
public void testComparatorWithDoubleMetaphone() throws Exception {
@@ -71,4 +62,13 @@ public class StringEncoderComparatorTest {
"Trying to compare objects that make no sense to the underlying encoder" +
" should return a zero compare code");
}
+
+ @Test
+ public void testComparatorWithSoundex() throws Exception {
+ final StringEncoderComparator sCompare =
+ new StringEncoderComparator( new Soundex() );
+
+ assertEquals(0, sCompare.compare("O'Brien", "O'Brian"),
+ "O'Brien and O'Brian didn't come out with the same Soundex, something must be wrong here");
+ }
}
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 6afdcb93..53856f0a 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base16Test.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base16Test.java
@@ -45,6 +45,12 @@ public class Base16Test {
private final Random random = new Random();
+ @Test
+ public void checkEncodeLengthBounds() {
+ final Base16 base16 = new Base16();
+ assertThrows(IllegalArgumentException.class, () -> base16.encode(new byte[10], 0, 1 << 30));
+ }
+
/**
* @return Returns the random.
*/
@@ -67,11 +73,6 @@ public class Base16Test {
assertEquals(content, decodedContent, "decoding hello world");
}
- @Test
- public void testBase16AtBufferStart() {
- testBase16InBuffer(0, 100);
- }
-
@Test
public void testBase16AtBufferEnd() {
testBase16InBuffer(100, 0);
@@ -82,6 +83,11 @@ public class Base16Test {
testBase16InBuffer(100, 100);
}
+ @Test
+ public void testBase16AtBufferStart() {
+ testBase16InBuffer(0, 100);
+ }
+
private void testBase16InBuffer(final int startPasSize, final int endPadSize) {
final String content = "Hello World";
final String encodedContent;
@@ -93,6 +99,21 @@ public class Base16Test {
assertEquals("48656C6C6F20576F726C64", encodedContent, "encoding hello world");
}
+ @Test
+ public void testByteToStringVariations() {
+ final Base16 base16 = new Base16();
+ final byte[] b1 = StringUtils.getBytesUtf8("Hello World");
+ final byte[] b2 = {};
+ final byte[] b3 = null;
+
+ assertEquals("48656C6C6F20576F726C64", base16.encodeToString(b1), "byteToString Hello World");
+ assertEquals("48656C6C6F20576F726C64", StringUtils.newStringUtf8(new Base16().encode(b1)), "byteToString static Hello World");
+ assertEquals("", base16.encodeToString(b2), "byteToString \"\"");
+ assertEquals("", StringUtils.newStringUtf8(new Base16().encode(b2)), "byteToString static \"\"");
+ assertNull(base16.encodeToString(b3), "byteToString null");
+ assertNull(StringUtils.newStringUtf8(new Base16().encode(b3)), "byteToString static null");
+ }
+
/**
* isBase16 throws RuntimeException on some
* non-Base16 bytes
@@ -104,15 +125,6 @@ public class Base16Test {
assertThrows(RuntimeException.class, () -> b16.decode(x));
}
- @Test
- public void testConstructors() {
- new Base16();
- new Base16(false);
- new Base16(true);
- new Base16(false, CodecPolicy.LENIENT);
- new Base16(false, CodecPolicy.STRICT);
- }
-
@Test
public void testConstructor_LowerCase() {
final Base16 base16 = new Base16(true);
@@ -131,6 +143,67 @@ public class Base16Test {
assertEquals(result, expectedResult, "new base16(false, CodecPolicy.STRICT)");
}
+ @Test
+ public void testConstructors() {
+ new Base16();
+ new Base16(false);
+ new Base16(true);
+ new Base16(false, CodecPolicy.LENIENT);
+ new Base16(false, CodecPolicy.STRICT);
+ }
+
+ @Test
+ public void testDecodeSingleBytes() {
+ final String encoded = "556E74696C206E6578742074696D6521";
+
+ final BaseNCodec.Context context = new BaseNCodec.Context();
+ final Base16 b16 = new Base16();
+
+ final byte[] encocdedBytes = StringUtils.getBytesUtf8(encoded);
+
+ // decode byte-by-byte
+ b16.decode(encocdedBytes, 0, 1, context);
+ b16.decode(encocdedBytes, 1, 1, context); // yields "U"
+ b16.decode(encocdedBytes, 2, 1, context);
+ b16.decode(encocdedBytes, 3, 1, context); // yields "n"
+
+ // decode split hex-pairs
+ b16.decode(encocdedBytes, 4, 3, context); // yields "t"
+ b16.decode(encocdedBytes, 7, 3, context); // yields "il"
+ b16.decode(encocdedBytes, 10, 3, context); // yields " "
+
+ // decode remaining
+ b16.decode(encocdedBytes, 13, 19, context); // yields "next time!"
+
+ final byte[] decodedBytes = new byte[context.pos];
+ System.arraycopy(context.buffer, context.readPos, decodedBytes, 0, decodedBytes.length);
+ final String decoded = StringUtils.newStringUtf8(decodedBytes);
+
+ assertEquals("Until next time!", decoded);
+ }
+
+ @Test
+ public void testDecodeSingleBytesOptimisation() {
+ final BaseNCodec.Context context = new BaseNCodec.Context();
+ assertEquals(0, context.ibitWorkArea);
+ assertNull(context.buffer);
+
+ final byte[] data = new byte[1];
+
+ final Base16 b16 = new Base16();
+
+ data[0] = (byte) 'E';
+ b16.decode(data, 0, 1, context);
+ assertEquals(15, context.ibitWorkArea);
+ assertNull(context.buffer);
+
+ data[0] = (byte) 'F';
+ b16.decode(data, 0, 1, context);
+ assertEquals(0, context.ibitWorkArea);
+
+ assertEquals((byte)0xEF, context.buffer[0]);
+ }
+
/**
* Test encode and decode of empty byte array.
*/
@@ -175,6 +248,53 @@ public class Base16Test {
}
}
+ @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
+ b16 = new Base16(true);
+ for (char c = '0'; c <= '9'; c++) {
+ assertTrue(b16.isInAlphabet((byte) c));
+ }
+ for (char c = 'a'; c <= 'f'; c++) {
+ assertTrue(b16.isInAlphabet((byte) c));
+ }
+ for (char c = 'A'; c <= 'F'; c++) {
+ assertFalse(b16.isInAlphabet((byte) c));
+ }
+ assertFalse(b16.isInAlphabet((byte) ('0' - 1)));
+ assertFalse(b16.isInAlphabet((byte) ('9' + 1)));
+ assertFalse(b16.isInAlphabet((byte) ('a' - 1)));
+ assertFalse(b16.isInAlphabet((byte) ('f' + 1)));
+ assertFalse(b16.isInAlphabet((byte) ('z' + 1)));
+
+ // upper-case
+ b16 = new Base16(false);
+ for (char c = '0'; c <= '9'; c++) {
+ assertTrue(b16.isInAlphabet((byte) c));
+ }
+ for (char c = 'a'; c <= 'f'; c++) {
+ assertFalse(b16.isInAlphabet((byte) c));
+ }
+ for (char c = 'A'; c <= 'F'; c++) {
+ assertTrue(b16.isInAlphabet((byte) c));
+ }
+ assertFalse(b16.isInAlphabet((byte) ('0' - 1)));
+ assertFalse(b16.isInAlphabet((byte) ('9' + 1)));
+ assertFalse(b16.isInAlphabet((byte) ('A' - 1)));
+ assertFalse(b16.isInAlphabet((byte) ('F' + 1)));
+ assertFalse(b16.isInAlphabet((byte) ('Z' + 1)));
+ }
+
@Test
public void testKnownDecodings() {
assertEquals("The quick brown fox jumped over the lazy dogs.", new String(new Base16(true).decode(
@@ -205,6 +325,17 @@ public class Base16Test {
assertEquals("78797a7a7921", new String(new Base16(true).encode("xyzzy!".getBytes(CHARSET_UTF8))));
}
+ @Test
+ 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, CodecPolicy.LENIENT);
+ assertEquals(CodecPolicy.LENIENT, b16.getCodecPolicy());
+
+ final byte[] decoded = b16.decode(StringUtils.getBytesUtf8(encoded));
+ assertArrayEquals(new byte[] {(byte)0xaa, (byte)0xbb, (byte)0xcc, (byte)0xdd}, decoded);
+ }
+
@Test
public void testNonBase16Test() {
final byte[] invalidEncodedChars = { '/', ':', '@', 'G', '%', '`', 'g' };
@@ -234,6 +365,12 @@ public class Base16Test {
assertEquals(original, dest, "dest string does not equal original");
}
+ @Test
+ public void testObjectEncode() {
+ final Base16 b16 = new Base16();
+ assertEquals(new String(b16.encode("Hello World".getBytes(CHARSET_UTF8))), "48656C6C6F20576F726C64");
+ }
+
@Test
public void testObjectEncodeWithInvalidParameter() {
assertThrows(EncoderException.class, () -> new Base16().encode("Yadayadayada"));
@@ -252,9 +389,24 @@ public class Base16Test {
}
@Test
- public void testObjectEncode() {
- final Base16 b16 = new Base16();
- assertEquals(new String(b16.encode("Hello World".getBytes(CHARSET_UTF8))), "48656C6C6F20576F726C64");
+ public void testOddEvenDecoding() {
+ final String encoded = "4142434445";
+
+ final BaseNCodec.Context context = new BaseNCodec.Context();
+ final Base16 base16 = new Base16();
+
+ final byte[] encodedBytes = StringUtils.getBytesUtf8(encoded);
+
+ // pass odd, then even, then odd amount of data
+ base16.decode(encodedBytes, 0, 3, context);
+ base16.decode(encodedBytes, 3, 4, context);
+ base16.decode(encodedBytes, 7, 3, context);
+
+ final byte[] decodedBytes = new byte[context.pos];
+ System.arraycopy(context.buffer, context.readPos, decodedBytes, 0, decodedBytes.length);
+ final String decoded = StringUtils.newStringUtf8(decodedBytes);
+
+ assertEquals("ABCDE", decoded);
}
@Test
@@ -397,38 +549,12 @@ public class Base16Test {
}
@Test
- public void testTriplets() {
- 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
- public void testByteToStringVariations() {
- final Base16 base16 = new Base16();
- final byte[] b1 = StringUtils.getBytesUtf8("Hello World");
- final byte[] b2 = {};
- final byte[] b3 = null;
+ 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
- assertEquals("48656C6C6F20576F726C64", base16.encodeToString(b1), "byteToString Hello World");
- assertEquals("48656C6C6F20576F726C64", StringUtils.newStringUtf8(new Base16().encode(b1)), "byteToString static Hello World");
- assertEquals("", base16.encodeToString(b2), "byteToString \"\"");
- assertEquals("", StringUtils.newStringUtf8(new Base16().encode(b2)), "byteToString static \"\"");
- assertNull(base16.encodeToString(b3), "byteToString null");
- assertNull(StringUtils.newStringUtf8(new Base16().encode(b3)), "byteToString static null");
+ final Base16 b16 = new Base16(true, CodecPolicy.STRICT);
+ assertEquals(CodecPolicy.STRICT, b16.getCodecPolicy());
+ assertThrows(IllegalArgumentException.class, () -> b16.decode(StringUtils.getBytesUtf8(encoded)));
}
@Test
@@ -447,6 +573,26 @@ public class Base16Test {
assertNull(StringUtils.newStringUtf8(new Base16().decode(s3)), "StringToByte static null");
}
+ @Test
+ public void testTriplets() {
+ 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 })));
+ }
+
private String toString(final byte[] data) {
final StringBuilder buf = new StringBuilder();
for (int i = 0; i < data.length; i++) {
@@ -457,150 +603,4 @@ public class Base16Test {
}
return buf.toString();
}
-
- @Test
- public void checkEncodeLengthBounds() {
- final Base16 base16 = new Base16();
- assertThrows(IllegalArgumentException.class, () -> base16.encode(new byte[10], 0, 1 << 30));
- }
-
- @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
- b16 = new Base16(true);
- for (char c = '0'; c <= '9'; c++) {
- assertTrue(b16.isInAlphabet((byte) c));
- }
- for (char c = 'a'; c <= 'f'; c++) {
- assertTrue(b16.isInAlphabet((byte) c));
- }
- for (char c = 'A'; c <= 'F'; c++) {
- assertFalse(b16.isInAlphabet((byte) c));
- }
- assertFalse(b16.isInAlphabet((byte) ('0' - 1)));
- assertFalse(b16.isInAlphabet((byte) ('9' + 1)));
- assertFalse(b16.isInAlphabet((byte) ('a' - 1)));
- assertFalse(b16.isInAlphabet((byte) ('f' + 1)));
- assertFalse(b16.isInAlphabet((byte) ('z' + 1)));
-
- // upper-case
- b16 = new Base16(false);
- for (char c = '0'; c <= '9'; c++) {
- assertTrue(b16.isInAlphabet((byte) c));
- }
- for (char c = 'a'; c <= 'f'; c++) {
- assertFalse(b16.isInAlphabet((byte) c));
- }
- for (char c = 'A'; c <= 'F'; c++) {
- assertTrue(b16.isInAlphabet((byte) c));
- }
- assertFalse(b16.isInAlphabet((byte) ('0' - 1)));
- assertFalse(b16.isInAlphabet((byte) ('9' + 1)));
- assertFalse(b16.isInAlphabet((byte) ('A' - 1)));
- assertFalse(b16.isInAlphabet((byte) ('F' + 1)));
- assertFalse(b16.isInAlphabet((byte) ('Z' + 1)));
- }
-
- @Test
- public void testDecodeSingleBytes() {
- final String encoded = "556E74696C206E6578742074696D6521";
-
- final BaseNCodec.Context context = new BaseNCodec.Context();
- final Base16 b16 = new Base16();
-
- final byte[] encocdedBytes = StringUtils.getBytesUtf8(encoded);
-
- // decode byte-by-byte
- b16.decode(encocdedBytes, 0, 1, context);
- b16.decode(encocdedBytes, 1, 1, context); // yields "U"
- b16.decode(encocdedBytes, 2, 1, context);
- b16.decode(encocdedBytes, 3, 1, context); // yields "n"
-
- // decode split hex-pairs
- b16.decode(encocdedBytes, 4, 3, context); // yields "t"
- b16.decode(encocdedBytes, 7, 3, context); // yields "il"
- b16.decode(encocdedBytes, 10, 3, context); // yields " "
-
- // decode remaining
- b16.decode(encocdedBytes, 13, 19, context); // yields "next time!"
-
- final byte[] decodedBytes = new byte[context.pos];
- System.arraycopy(context.buffer, context.readPos, decodedBytes, 0, decodedBytes.length);
- final String decoded = StringUtils.newStringUtf8(decodedBytes);
-
- assertEquals("Until next time!", decoded);
- }
-
- @Test
- public void testDecodeSingleBytesOptimisation() {
- final BaseNCodec.Context context = new BaseNCodec.Context();
- assertEquals(0, context.ibitWorkArea);
- assertNull(context.buffer);
-
- final byte[] data = new byte[1];
-
- final Base16 b16 = new Base16();
-
- data[0] = (byte) 'E';
- b16.decode(data, 0, 1, context);
- assertEquals(15, context.ibitWorkArea);
- assertNull(context.buffer);
-
- data[0] = (byte) 'F';
- b16.decode(data, 0, 1, context);
- assertEquals(0, context.ibitWorkArea);
-
- assertEquals((byte)0xEF, context.buffer[0]);
- }
-
- @Test
- 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, CodecPolicy.STRICT);
- assertEquals(CodecPolicy.STRICT, b16.getCodecPolicy());
- assertThrows(IllegalArgumentException.class, () -> b16.decode(StringUtils.getBytesUtf8(encoded)));
- }
-
- @Test
- 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, CodecPolicy.LENIENT);
- assertEquals(CodecPolicy.LENIENT, b16.getCodecPolicy());
-
- final byte[] decoded = b16.decode(StringUtils.getBytesUtf8(encoded));
- assertArrayEquals(new byte[] {(byte)0xaa, (byte)0xbb, (byte)0xcc, (byte)0xdd}, decoded);
- }
-
- @Test
- public void testOddEvenDecoding() {
- final String encoded = "4142434445";
-
- final BaseNCodec.Context context = new BaseNCodec.Context();
- final Base16 base16 = new Base16();
-
- final byte[] encodedBytes = StringUtils.getBytesUtf8(encoded);
-
- // pass odd, then even, then odd amount of data
- base16.decode(encodedBytes, 0, 3, context);
- base16.decode(encodedBytes, 3, 4, context);
- base16.decode(encodedBytes, 7, 3, context);
-
- final byte[] decodedBytes = new byte[context.pos];
- System.arraycopy(context.buffer, context.readPos, decodedBytes, 0, decodedBytes.length);
- final String decoded = StringUtils.newStringUtf8(decodedBytes);
-
- assertEquals("ABCDE", decoded);
- }
}
diff --git a/src/test/java/org/apache/commons/codec/binary/Base32InputStreamTest.java b/src/test/java/org/apache/commons/codec/binary/Base32InputStreamTest.java
index 06248f61..81e17d24 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base32InputStreamTest.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base32InputStreamTest.java
@@ -42,36 +42,30 @@ public class Base32InputStreamTest {
private static final String STRING_FIXTURE = "Hello World";
/**
- * Tests the problem reported in CODEC-130. Missing / wrong implementation of skip.
+ * Tests skipping past the end of a stream.
+ *
+ * @throws Throwable
+ * for some failure scenarios.
*/
@Test
- public void testCodec130() throws IOException {
- final ByteArrayOutputStream bos = new ByteArrayOutputStream();
- try (final Base32OutputStream base32os = new Base32OutputStream(bos)) {
- base32os.write(StringUtils.getBytesUtf8(STRING_FIXTURE));
+ public void testAvailable() throws Throwable {
+ final InputStream ins = new ByteArrayInputStream(StringUtils.getBytesIso8859_1(ENCODED_FOO));
+ try (final Base32InputStream b32stream = new Base32InputStream(ins)) {
+ assertEquals(1, b32stream.available());
+ assertEquals(3, b32stream.skip(10));
+ // End of stream reached
+ assertEquals(0, b32stream.available());
+ assertEquals(-1, b32stream.read());
+ assertEquals(-1, b32stream.read());
+ assertEquals(0, b32stream.available());
}
-
- final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
- final Base32InputStream ins = new Base32InputStream(bis);
-
- // we skip the first character read from the reader
- ins.skip(1);
- final byte[] decodedBytes = BaseNTestData.streamToBytes(ins, new byte[64]);
- final String str = StringUtils.newStringUtf8(decodedBytes);
-
- assertEquals(STRING_FIXTURE.substring(1), str);
}
- /**
- * Tests the bug reported in CODEC-105. Bad interactions with InputStream when reading one byte at a time.
- */
- @Test
- public void testCodec105() throws IOException {
- try (final Base32InputStream in = new Base32InputStream(new Codec105ErrorInputStream(), true, 0, null)) {
- for (int i = 0; i < 5; i++) {
- in.read();
- }
- }
+ private void testBase32EmptyInputStream(final int chuckSize) throws Exception {
+ final byte[] emptyEncoded = {};
+ final byte[] emptyDecoded = {};
+ testByteByByte(emptyEncoded, emptyDecoded, chuckSize, CRLF);
+ testByChunk(emptyEncoded, emptyDecoded, chuckSize, CRLF);
}
// /**
@@ -140,26 +134,6 @@ public class Base32InputStreamTest {
// );
// }
- /**
- * Tests skipping past the end of a stream.
- *
- * @throws Throwable
- * for some failure scenarios.
- */
- @Test
- public void testAvailable() throws Throwable {
- final InputStream ins = new ByteArrayInputStream(StringUtils.getBytesIso8859_1(ENCODED_FOO));
- try (final Base32InputStream b32stream = new Base32InputStream(ins)) {
- assertEquals(1, b32stream.available());
- assertEquals(3, b32stream.skip(10));
- // End of stream reached
- assertEquals(0, b32stream.available());
- assertEquals(-1, b32stream.read());
- assertEquals(-1, b32stream.read());
- assertEquals(0, b32stream.available());
- }
- }
-
/**
* Tests the Base32InputStream implementation against empty input.
*
@@ -182,13 +156,6 @@ public class Base32InputStreamTest {
testBase32EmptyInputStream(BaseNCodec.PEM_CHUNK_SIZE);
}
- private void testBase32EmptyInputStream(final int chuckSize) throws Exception {
- final byte[] emptyEncoded = {};
- final byte[] emptyDecoded = {};
- testByteByByte(emptyEncoded, emptyDecoded, chuckSize, CRLF);
- testByChunk(emptyEncoded, emptyDecoded, chuckSize, CRLF);
- }
-
/**
* Tests the Base32InputStream implementation.
*
@@ -377,6 +344,39 @@ public class Base32InputStreamTest {
assertArrayEquals(decoded, output, "Streaming base32 wrap-wrap-wrap!");
}
+ /**
+ * Tests the bug reported in CODEC-105. Bad interactions with InputStream when reading one byte at a time.
+ */
+ @Test
+ public void testCodec105() throws IOException {
+ try (final Base32InputStream in = new Base32InputStream(new Codec105ErrorInputStream(), true, 0, null)) {
+ for (int i = 0; i < 5; i++) {
+ in.read();
+ }
+ }
+ }
+
+ /**
+ * Tests the problem reported in CODEC-130. Missing / wrong implementation of skip.
+ */
+ @Test
+ public void testCodec130() throws IOException {
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ try (final Base32OutputStream base32os = new Base32OutputStream(bos)) {
+ base32os.write(StringUtils.getBytesUtf8(STRING_FIXTURE));
+ }
+
+ final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+ final Base32InputStream ins = new Base32InputStream(bis);
+
+ // we skip the first character read from the reader
+ ins.skip(1);
+ final byte[] decodedBytes = BaseNTestData.streamToBytes(ins, new byte[64]);
+ final String str = StringUtils.newStringUtf8(decodedBytes);
+
+ assertEquals(STRING_FIXTURE.substring(1), str);
+ }
+
/**
* Tests markSupported.
*
@@ -446,38 +446,38 @@ public class Base32InputStreamTest {
}
/**
- * Tests skipping as a noop
+ * Tests skipping number of characters larger than the internal buffer.
*
* @throws Throwable
* for some failure scenarios.
*/
@Test
- public void testSkipNone() throws Throwable {
+ public void testSkipBig() throws Throwable {
final InputStream ins = new ByteArrayInputStream(StringUtils.getBytesIso8859_1(ENCODED_FOO));
try (final Base32InputStream b32stream = new Base32InputStream(ins)) {
- final byte[] actualBytes = new byte[6];
- assertEquals(0, b32stream.skip(0));
- b32stream.read(actualBytes, 0, actualBytes.length);
- assertArrayEquals(actualBytes, new byte[] { 102, 111, 111, 0, 0, 0 });
+ assertEquals(3, b32stream.skip(1024));
// End of stream reached
assertEquals(-1, b32stream.read());
+ assertEquals(-1, b32stream.read());
}
}
/**
- * Tests skipping number of characters larger than the internal buffer.
+ * Tests skipping as a noop
*
* @throws Throwable
* for some failure scenarios.
*/
@Test
- public void testSkipBig() throws Throwable {
+ public void testSkipNone() throws Throwable {
final InputStream ins = new ByteArrayInputStream(StringUtils.getBytesIso8859_1(ENCODED_FOO));
try (final Base32InputStream b32stream = new Base32InputStream(ins)) {
- assertEquals(3, b32stream.skip(1024));
+ final byte[] actualBytes = new byte[6];
+ assertEquals(0, b32stream.skip(0));
+ b32stream.read(actualBytes, 0, actualBytes.length);
+ assertArrayEquals(actualBytes, new byte[] { 102, 111, 111, 0, 0, 0 });
// End of stream reached
assertEquals(-1, b32stream.read());
- assertEquals(-1, b32stream.read());
}
}
diff --git a/src/test/java/org/apache/commons/codec/binary/Base32OutputStreamTest.java b/src/test/java/org/apache/commons/codec/binary/Base32OutputStreamTest.java
index 8cb10449..d935e7d7 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base32OutputStreamTest.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base32OutputStreamTest.java
@@ -60,6 +60,13 @@ public class Base32OutputStreamTest {
// }
+ private void testBase32EmptyOutputStream(final int chunkSize) throws Exception {
+ final byte[] emptyEncoded = {};
+ final byte[] emptyDecoded = {};
+ testByteByByte(emptyEncoded, emptyDecoded, chunkSize, CR_LF);
+ testByChunk(emptyEncoded, emptyDecoded, chunkSize, CR_LF);
+ }
+
/**
* Test the Base32OutputStream implementation against empty input.
*
@@ -82,13 +89,6 @@ public class Base32OutputStreamTest {
testBase32EmptyOutputStream(BaseNCodec.PEM_CHUNK_SIZE);
}
- private void testBase32EmptyOutputStream(final int chunkSize) throws Exception {
- final byte[] emptyEncoded = {};
- final byte[] emptyDecoded = {};
- testByteByByte(emptyEncoded, emptyDecoded, chunkSize, CR_LF);
- testByChunk(emptyEncoded, emptyDecoded, chunkSize, CR_LF);
- }
-
/**
* Test the Base32OutputStream implementation
*
@@ -276,6 +276,34 @@ public class Base32OutputStreamTest {
assertArrayEquals(decoded, output, "Streaming byte-by-byte Base32 wrap-wrap-wrap!");
}
+ /**
+ * Test strict decoding.
+ *
+ * @throws Exception
+ * for some failure scenarios.
+ */
+ @Test
+ public void testStrictDecoding() throws Exception {
+ for (final String s : Base32Test.BASE32_IMPOSSIBLE_CASES) {
+ final byte[] encoded = StringUtils.getBytesUtf8(s);
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ try (Base32OutputStream out = new Base32OutputStream(bout, false)) {
+ // Default is lenient decoding; it should not throw
+ assertFalse(out.isStrictDecoding());
+ out.write(encoded);
+ out.close();
+ assertTrue(bout.size() > 0);
+
+ // Strict decoding should throw
+ bout = new ByteArrayOutputStream();
+ try (final Base32OutputStream out2 = new Base32OutputStream(bout, false, 0, null, CodecPolicy.STRICT)) {
+ assertTrue(out2.isStrictDecoding());
+ assertThrows(IllegalArgumentException.class, () -> out2.write(encoded));
+ }
+ }
+ }
+ }
+
/**
* Tests Base32OutputStream.write for expected IndexOutOfBoundsException conditions.
*
@@ -307,32 +335,4 @@ public class Base32OutputStreamTest {
assertThrows(NullPointerException.class, () -> out.write(null, 0, 0));
}
}
-
- /**
- * Test strict decoding.
- *
- * @throws Exception
- * for some failure scenarios.
- */
- @Test
- public void testStrictDecoding() throws Exception {
- for (final String s : Base32Test.BASE32_IMPOSSIBLE_CASES) {
- final byte[] encoded = StringUtils.getBytesUtf8(s);
- ByteArrayOutputStream bout = new ByteArrayOutputStream();
- try (Base32OutputStream out = new Base32OutputStream(bout, false)) {
- // Default is lenient decoding; it should not throw
- assertFalse(out.isStrictDecoding());
- out.write(encoded);
- out.close();
- assertTrue(bout.size() > 0);
-
- // Strict decoding should throw
- bout = new ByteArrayOutputStream();
- try (final Base32OutputStream out2 = new Base32OutputStream(bout, false, 0, null, CodecPolicy.STRICT)) {
- assertTrue(out2.isStrictDecoding());
- assertThrows(IllegalArgumentException.class, () -> out2.write(encoded));
- }
- }
- }
- }
}
diff --git a/src/test/java/org/apache/commons/codec/binary/Base32Test.java b/src/test/java/org/apache/commons/codec/binary/Base32Test.java
index d0c892c2..6c059c31 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base32Test.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base32Test.java
@@ -138,9 +138,57 @@ public class Base32Test {
{"foobar" ,"MZXW6YTBOI%%%%%%"},
};
- @Test
- public void testBase32AtBufferStart() {
- testBase32InBuffer(0, 100);
+ /**
+ * Test base 32 decoding of the final trailing bits. Trailing encoded bytes
+ * cannot fit exactly into 5-bit characters so the last character has a limited
+ * alphabet where the final bits are zero. This asserts that illegal final
+ * characters throw an exception when decoding.
+ *
+ * @param nbits the number of trailing bits (must be a factor of 5 and {@code <40})
+ */
+ private static void assertBase32DecodingOfTrailingBits(final int nbits) {
+ // Requires strict decoding
+ final Base32 codec = new Base32(0, null, false, BaseNCodec.PAD_DEFAULT, CodecPolicy.STRICT);
+ assertTrue(codec.isStrictDecoding());
+ assertEquals(CodecPolicy.STRICT, codec.getCodecPolicy());
+ // A lenient decoder should not re-encode to the same bytes
+ final Base32 defaultCodec = new Base32();
+ assertFalse(defaultCodec.isStrictDecoding());
+ assertEquals(CodecPolicy.LENIENT, defaultCodec.getCodecPolicy());
+
+ // Create the encoded bytes. The first characters must be valid so fill with 'zero'
+ // then pad to the block size.
+ final int length = nbits / 5;
+ final byte[] encoded = new byte[8];
+ Arrays.fill(encoded, 0, length, ENCODE_TABLE[0]);
+ Arrays.fill(encoded, length, encoded.length, (byte) '=');
+ // Compute how many bits would be discarded from 8-bit bytes
+ final int discard = nbits % 8;
+ final int emptyBitsMask = (1 << discard) - 1;
+ // Special case when an impossible number of trailing characters
+ final boolean invalid = length == 1 || length == 3 || length == 6;
+ // Enumerate all 32 possible final characters in the last position
+ final int last = length - 1;
+ for (int i = 0; i < 32; i++) {
+ encoded[last] = ENCODE_TABLE[i];
+ // If the lower bits are set we expect an exception. This is not a valid
+ // final character.
+ if (invalid || (i & emptyBitsMask) != 0) {
+ assertThrows(IllegalArgumentException.class, () -> codec.decode(encoded), "Final base-32 digit should not be allowed");
+ // The default lenient mode should decode this
+ final byte[] decoded = defaultCodec.decode(encoded);
+ // Re-encoding should not match the original array as it was invalid
+ assertFalse(Arrays.equals(encoded, defaultCodec.encode(decoded)));
+ } else {
+ // Otherwise this should decode
+ final byte[] decoded = codec.decode(encoded);
+ // Compute the bits that were encoded. This should match the final decoded byte.
+ final int bitsEncoded = i >> discard;
+ assertEquals(bitsEncoded, decoded[decoded.length - 1], "Invalid decoding of last character");
+ // Re-encoding should match the original array (requires the same padding character)
+ assertArrayEquals(encoded, codec.encode(decoded));
+ }
+ }
}
@Test
@@ -153,13 +201,30 @@ public class Base32Test {
testBase32InBuffer(100, 100);
}
- private void testBase32InBuffer(final int startPasSize, final int endPadSize) {
+ @Test
+ public void testBase32AtBufferStart() {
+ testBase32InBuffer(0, 100);
+ }
+
+ @Test
+ public void testBase32BinarySamples() throws Exception {
final Base32 codec = new Base32();
- for (final String[] element : BASE32_TEST_CASES) {
- final byte[] bytes = element[0].getBytes(CHARSET_UTF8);
- byte[] buffer = ArrayUtils.addAll(bytes, new byte[endPadSize]);
- buffer = ArrayUtils.addAll(new byte[startPasSize], buffer);
- assertEquals(element[1], StringUtils.newStringUtf8(codec.encode(buffer, startPasSize, bytes.length)));
+ for (final Object[] element : BASE32_BINARY_TEST_CASES) {
+ final String expected;
+ if (element.length > 2) {
+ expected = (String)element[2];
+ } else {
+ expected = (String)element[1];
+ }
+ assertEquals(expected.toUpperCase(), codec.encodeAsString((byte[])element[0]));
+ }
+ }
+
+ @Test
+ public void testBase32BinarySamplesReverse() throws Exception {
+ final Base32 codec = new Base32();
+ for (final Object[] element : BASE32_BINARY_TEST_CASES) {
+ assertArrayEquals((byte[])element[0], codec.decode((String)element[1]));
}
}
@@ -171,6 +236,47 @@ public class Base32Test {
}
}
+ @Test
+ public void testBase32DecodingOfTrailing10Bits() {
+ assertBase32DecodingOfTrailingBits(10);
+ }
+
+ @Test
+ public void testBase32DecodingOfTrailing15Bits() {
+ assertBase32DecodingOfTrailingBits(15);
+ }
+
+ @Test
+ public void testBase32DecodingOfTrailing20Bits() {
+ assertBase32DecodingOfTrailingBits(20);
+ }
+
+ @Test
+ public void testBase32DecodingOfTrailing25Bits() {
+ assertBase32DecodingOfTrailingBits(25);
+ }
+
+ @Test
+ public void testBase32DecodingOfTrailing30Bits() {
+ assertBase32DecodingOfTrailingBits(30);
+ }
+
+ @Test
+ public void testBase32DecodingOfTrailing35Bits() {
+ assertBase32DecodingOfTrailingBits(35);
+ }
+
+ @Test
+ public void testBase32DecodingOfTrailing5Bits() {
+ assertBase32DecodingOfTrailingBits(5);
+ }
+
+ @Test
+ public void testBase32HexImpossibleSamples() {
+ testImpossibleCases(new Base32(0, null, true, BaseNCodec.PAD_DEFAULT, CodecPolicy.STRICT),
+ BASE32HEX_IMPOSSIBLE_CASES);
+ }
+
@Test
public void testBase32HexSamples() throws Exception {
final Base32 codec = new Base32(true);
@@ -196,32 +302,33 @@ public class Base32Test {
}
@Test
- public void testBase32Samples() throws Exception {
- final Base32 codec = new Base32();
- for (final String[] element : BASE32_TEST_CASES) {
- assertEquals(element[1], codec.encodeAsString(element[0].getBytes(CHARSET_UTF8)));
- }
+ public void testBase32ImpossibleChunked() {
+ testImpossibleCases(
+ new Base32(20, BaseNCodec.CHUNK_SEPARATOR, false, BaseNCodec.PAD_DEFAULT, CodecPolicy.STRICT),
+ BASE32_IMPOSSIBLE_CASES_CHUNKED);
}
@Test
- public void testBase32BinarySamples() throws Exception {
+ public void testBase32ImpossibleSamples() {
+ testImpossibleCases(new Base32(0, null, false, BaseNCodec.PAD_DEFAULT, CodecPolicy.STRICT),
+ BASE32_IMPOSSIBLE_CASES);
+ }
+
+ private void testBase32InBuffer(final int startPasSize, final int endPadSize) {
final Base32 codec = new Base32();
- for (final Object[] element : BASE32_BINARY_TEST_CASES) {
- final String expected;
- if (element.length > 2) {
- expected = (String)element[2];
- } else {
- expected = (String)element[1];
- }
- assertEquals(expected.toUpperCase(), codec.encodeAsString((byte[])element[0]));
+ for (final String[] element : BASE32_TEST_CASES) {
+ final byte[] bytes = element[0].getBytes(CHARSET_UTF8);
+ byte[] buffer = ArrayUtils.addAll(bytes, new byte[endPadSize]);
+ buffer = ArrayUtils.addAll(new byte[startPasSize], buffer);
+ assertEquals(element[1], StringUtils.newStringUtf8(codec.encode(buffer, startPasSize, bytes.length)));
}
}
@Test
- public void testBase32BinarySamplesReverse() throws Exception {
+ public void testBase32Samples() throws Exception {
final Base32 codec = new Base32();
- for (final Object[] element : BASE32_BINARY_TEST_CASES) {
- assertArrayEquals((byte[])element[0], codec.decode((String)element[1]));
+ for (final String[] element : BASE32_TEST_CASES) {
+ assertEquals(element[1], codec.encodeAsString(element[0].getBytes(CHARSET_UTF8)));
}
}
@@ -282,6 +389,12 @@ public class Base32Test {
assertNull(new Base32().decode((byte[]) null), "empty Base32 encode");
}
+ private void testImpossibleCases(final Base32 codec, final String[] impossible_cases) {
+ for (final String impossible : impossible_cases) {
+ assertThrows(IllegalArgumentException.class, () -> codec.decode(impossible));
+ }
+ }
+
@Test
public void testIsInAlphabet() {
// invalid bounds
@@ -379,117 +492,4 @@ public class Base32Test {
}
}
}
-
- @Test
- public void testBase32ImpossibleSamples() {
- testImpossibleCases(new Base32(0, null, false, BaseNCodec.PAD_DEFAULT, CodecPolicy.STRICT),
- BASE32_IMPOSSIBLE_CASES);
- }
-
- @Test
- public void testBase32ImpossibleChunked() {
- testImpossibleCases(
- new Base32(20, BaseNCodec.CHUNK_SEPARATOR, false, BaseNCodec.PAD_DEFAULT, CodecPolicy.STRICT),
- BASE32_IMPOSSIBLE_CASES_CHUNKED);
- }
-
- @Test
- public void testBase32HexImpossibleSamples() {
- testImpossibleCases(new Base32(0, null, true, BaseNCodec.PAD_DEFAULT, CodecPolicy.STRICT),
- BASE32HEX_IMPOSSIBLE_CASES);
- }
-
- private void testImpossibleCases(final Base32 codec, final String[] impossible_cases) {
- for (final String impossible : impossible_cases) {
- assertThrows(IllegalArgumentException.class, () -> codec.decode(impossible));
- }
- }
-
- @Test
- public void testBase32DecodingOfTrailing5Bits() {
- assertBase32DecodingOfTrailingBits(5);
- }
-
- @Test
- public void testBase32DecodingOfTrailing10Bits() {
- assertBase32DecodingOfTrailingBits(10);
- }
-
- @Test
- public void testBase32DecodingOfTrailing15Bits() {
- assertBase32DecodingOfTrailingBits(15);
- }
-
- @Test
- public void testBase32DecodingOfTrailing20Bits() {
- assertBase32DecodingOfTrailingBits(20);
- }
-
- @Test
- public void testBase32DecodingOfTrailing25Bits() {
- assertBase32DecodingOfTrailingBits(25);
- }
-
- @Test
- public void testBase32DecodingOfTrailing30Bits() {
- assertBase32DecodingOfTrailingBits(30);
- }
-
- @Test
- public void testBase32DecodingOfTrailing35Bits() {
- assertBase32DecodingOfTrailingBits(35);
- }
-
- /**
- * Test base 32 decoding of the final trailing bits. Trailing encoded bytes
- * cannot fit exactly into 5-bit characters so the last character has a limited
- * alphabet where the final bits are zero. This asserts that illegal final
- * characters throw an exception when decoding.
- *
- * @param nbits the number of trailing bits (must be a factor of 5 and {@code <40})
- */
- private static void assertBase32DecodingOfTrailingBits(final int nbits) {
- // Requires strict decoding
- final Base32 codec = new Base32(0, null, false, BaseNCodec.PAD_DEFAULT, CodecPolicy.STRICT);
- assertTrue(codec.isStrictDecoding());
- assertEquals(CodecPolicy.STRICT, codec.getCodecPolicy());
- // A lenient decoder should not re-encode to the same bytes
- final Base32 defaultCodec = new Base32();
- assertFalse(defaultCodec.isStrictDecoding());
- assertEquals(CodecPolicy.LENIENT, defaultCodec.getCodecPolicy());
-
- // Create the encoded bytes. The first characters must be valid so fill with 'zero'
- // then pad to the block size.
- final int length = nbits / 5;
- final byte[] encoded = new byte[8];
- Arrays.fill(encoded, 0, length, ENCODE_TABLE[0]);
- Arrays.fill(encoded, length, encoded.length, (byte) '=');
- // Compute how many bits would be discarded from 8-bit bytes
- final int discard = nbits % 8;
- final int emptyBitsMask = (1 << discard) - 1;
- // Special case when an impossible number of trailing characters
- final boolean invalid = length == 1 || length == 3 || length == 6;
- // Enumerate all 32 possible final characters in the last position
- final int last = length - 1;
- for (int i = 0; i < 32; i++) {
- encoded[last] = ENCODE_TABLE[i];
- // If the lower bits are set we expect an exception. This is not a valid
- // final character.
- if (invalid || (i & emptyBitsMask) != 0) {
- assertThrows(IllegalArgumentException.class, () -> codec.decode(encoded), "Final base-32 digit should not be allowed");
- // The default lenient mode should decode this
- final byte[] decoded = defaultCodec.decode(encoded);
- // Re-encoding should not match the original array as it was invalid
- assertFalse(Arrays.equals(encoded, defaultCodec.encode(decoded)));
- } else {
- // Otherwise this should decode
- final byte[] decoded = codec.decode(encoded);
- // Compute the bits that were encoded. This should match the final decoded byte.
- final int bitsEncoded = i >> discard;
- assertEquals(bitsEncoded, decoded[decoded.length - 1], "Invalid decoding of last character");
- // Re-encoding should match the original array (requires the same padding character)
- assertArrayEquals(encoded, codec.encode(decoded));
- }
- }
- }
}
diff --git a/src/test/java/org/apache/commons/codec/binary/Base64Codec13Test.java b/src/test/java/org/apache/commons/codec/binary/Base64Codec13Test.java
index f194848a..f6f319a3 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base64Codec13Test.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base64Codec13Test.java
@@ -45,106 +45,106 @@ public class Base64Codec13Test {
initBYTES();
}
- /* These strings were generated from random byte[] arrays fed into commons-codec-1.3.jar */
- private static void initSTRINGS() {
- final String[] s = STRINGS;
- s[0] = "";
- s[1] = "uA==";
- s[2] = "z9w=";
- s[3] = "TQ+Z";
- s[4] = "bhjUYA==";
- s[5] = "1cO9td8=";
- s[6] = "sMxHoJf5";
- s[7] = "jQcPlDsZzw==";
- s[8] = "TAaPnfW/CYU=";
- s[9] = "cXTZuwzXPONS";
- s[10] = "Ltn/ZTV4IjT6OA==";
- s[11] = "6fh+jdU31SOmWrc=";
- s[12] = "E/5MoD4qCvDuTcFA";
- s[13] = "2n9YyfCMyMXembtssQ==";
- s[14] = "qBka3Bq6V31HmcmHjkY=";
- s[15] = "WvyZe6kQ8py7m25ucawJ";
- s[16] = "oYpxMy6BSpZXhVpOR6dXmA==";
- s[63] = "yexFaNKaP+VkVwEUvxQXbC0HSCi/srOY7c036lT25frs4xjIvp214JHCg7OL/XZW3IMe6CDgSMCaaI91eRgM";
- s[64] = "vkqgnuJ3plxNtoveiMJuYLN6wZQLpb3Fg48/zHkdFuDucuMKWVRO/niFRgKsFqcxq6VgCxwQbePiP9sRnxz7wg==";
- s[65] = "YHks3GCb2uVF47Y2tCieiDGJ879Rm5dBhQhQizYhfWOo+BrB2/K+E7wZWTid14lMpM60+5C0N9JNKAcBESeqZZI=";
- s[66] = "z8551jmQp/Qs95tw226+HCHWruKx/JvfBCfQ5p0fF77mkSpp66E552ik2gycrBBsMC/NbznAgTZoMzZxehfJwu49";
- s[67] = "VsR2whqq/qQm342+TNz1lgOZMoWbpCz+kj2zflq0nx7S/ReEVPUJcqgMtVzrr2FVQPfBAH5VRjR+hkxwv4bssQms8Q==";
- s[68] = "5xmIp8dUJZzkisIkuEPsnPXvzDeMo48qWFfHIn2av3jr5qoZHCs0LfNEyepC3v2sa0nCU0FlqsmDyTI5/2jt5zsLtV0=";
- s[69] = "tGEgXjglUB9NbCtiS88AetLtRqhCAnhzOUKVgvbJZHqOA6x8uOorA1t3NcaIA00ZqbPYALu4LzIm4i4lAL9QgiH/Jg7b";
- s[70] = "gFtxEhYJahDmU5dpudYs6ZTsqAx+s2j+06A0zeyb3U7nhZFsbkCDlds0EYUoqerZqZPm7F6CDOOD3dU7nYmelE0DxyMO9A==";
- s[71] = "j/h/1JygYA5bjttxzQxr5gBtgh+AYVozhF4WgvcU/g49v0hUy6FdhfZewGK+Phtzj7RabI5p2zXyzvkmLQdFhdI5Um4O5sw=";
- s[72] = "m+kYVGojIR5pgbz7pGJm2g+3qqk7fhl3cowa2eVrhki7WofyywnRezqTxOkBgVFz6nKs8qxpbbbzALctcPeMsp9dpXUfuUJr";
- s[73] = "pPaGnMr0UYmldnJVk/F+3WCJJ1r2otvD5KJdt2u1RnS6LwhHhwLCqfW8O/QEg43WdxKomGL/JM33tn/B9pMPoIU0QTGjq2GRow==";
- s[74] = "mOxzGyym6T/BxCV5nSiIYMlfAUmCN7gt7+ZTMg1kd8Ptirk+JF5dk8USbWBu/9ZvNg5ZuiJCeGwfaVpqpZ3K9ySF7C87Jvu1RUE=";
- s[75] = "VYLOIE4DnhxJn3FKS/2RHHHYLlZiGVdV/k4uBbtAYHUSTpRzaaYPGNAVjdNwbTHIihmeuk/5YQUy8NFsxIom+Li7bnWiBoHKBPP7";
- s[76] = "7foMpJ0TknCatjUiSxtnuKSiz4Qvl/idWY9UKiTljoQHZ+C8bcUscnI/bZr13e6AvyUh47MlpdGvzIm05qUdMWWLoZJOaGYvDmvrWQ==";
- s[77] = "jxQSGiFs+b1TfE4lDUAPUPJ0SWeUgl03rK6auieWJcarDIHM97gGOHMmyHudRMqkZmIkxYRgYgCCUg/JeU91OZD3tL4U+wNhShywe88=";
- s[78] = "UGmH/gl7t3Dk801vRhRDEbgsfShtHZ1gZQn4KNZ5Qsw3WiGjW0ImInVHa+LSHBzLUjwC0Z3nXO4i4+CiKYqAspOViE6WqVUY8ZSV0Og4";
- s[79] = "wdEoYmJuRng2z2IkAiSgJ1CW2VE7H7oXpYWEFFO8nG0bZn7PHhT8KyhaO2ridl8eUEysja0VXFDyQqSgZnvdUKrCGepWGZbw0/0bDws3Ag==";
- s[80] = "5kZqgrUbt+rN5BWAddeUtm9TGT43vYpB6PeyQwTyy9Vbr0+U/4Qzy0Iw37Ra293HmkmpgQzuScVpcIiFGXPAFWwToR+bovwu7aXji/FnMwk=";
- s[81] = "E467MMmJbmwv8Omc2TdcyMr/30B8izWbf+CAuJtw67b1g9trhC6n4GYnXjeW9DYvmWoIJPx0zvU/Q+gqv0cteg2bx9P2mrgMDARb6egowqjx";
- s[82] = "Vpt8hYb4jx1F+7REX7K65v6eO5F1GDg/K8SVLWDSp0srupYEQkBVRxnB9dmhSo9XHpz4C8pRl8r82fxXZummEf4U2Oh0Dip5rnNtDL+IJvL8lQ==";
- s[121] = "hf69xr9mtFf4N3j2uA9MgLL5Zy94Hjv+VQi94+LS8972JJgDHCQOwP5whdQkV+SJpXkiyHGaSsQ4fhepPwzuZcEpYER+beny1j+M0HSZe36MdRIhlTqno+4qsXckL0CjXsYkJJM0NAfOYjHAus5G1bgi9VhmiMfAMA==";
- s[122] = "yKzTh5hPp9/PBeZtrZXsFHAR9ywOM3hRaBDkgG9E09wFW8MZD0xMGegcp0QrTJcP8QYOaYhTDVimPqsNTVOmjdjkvS+2WhjJW4mVOXQ8KID91yaBtPo+DStL5GMgctcP5MoVf1Vp8w/mYtofqbllfDm5NfYzh2A7ijY=";
- s[123] = "csFmwvDzoO4IO6ySDA4B2V7emEetAwCgO66zzlfWb3KDrPfFZc3Jgr4+dlaUkEIDHYeLHETdTssWOl2KrPHBEsULpDTR+3OhurXb1Qr2NvHiHFuqT3Geb6EYw2albfTmXxch82ablt4WKl4qPcSey54v6tsCuUuZzrkt";
- s[124] = "5InxvKwpoCV7EK78OzU/tL9/NmK14Prw9tOCAyK+xpUNLZriuVEVdgpoZ05rliufaUDGHH8dPAem8G9DN/VOPktB6vXKtc2kMUgnMTiZwv/UVd+xyqnT8PLEdNQ8rCWxyiCcLdXFf0+xcE7qCcwzC+D7+cRW+i6dnpZkyw==";
- s[125] = "cEx7oTsSHWUFPj92cstdy5wGbRcxH+VRWN8kaNTTCPWqSckyU9Xk/jj5/gj9DFwjfsCSp60xutf4/rFanjtwqtRg6dJLP4JAgpOKswDlHi6Vt7zF/w7HidMf2sdtlsqzayZmT2Hn7iOo3CExzr5Z5JfmMFAX8R9peUN4t5U=";
- s[126] = "AeXetVbj+7mmGiCs3BGUSZDLlq2odMsN8JAHQM64Cly8y5jw75PpISocWRFFQmmXYP7ckKmtuhIvD69HtZxGhNRsl1l1gXzKFhsWykcRtG87F8sS1Uv/i6QvGiRIDVEGGIzWrzRIISkBb9wCxJ2HESfleWwrz/GqryjoN26B";
- s[127] = "aj1/8/+U8VO3D2iAwvQXZ4H0KwtuzDm4JCC8+22ccqk+UzKvqjGs87XngwfsMfSkeGVAi6VB6tfNJTjYctaj7R8dwh2PIfLSrvaphw4wNB2REjplnPojoOb9bNUNtUvdK3b1bArOWugIRJWLnMl72yEHFb1iBfBmn7uIa7KT2Q==";
- s[128] = "kiMuF/1CMRlgoS/uLKn1mNZFZNHJNkRQnivOrzj8HQAagwzvTXvsGgI9hXX3qaeZL9/x/Oq+Y5F6Dh+wXo+0kp6JagFjvbTJcQSowFzIwg7/V9sans0NE0Ejow5BfZKvihFI46sHiALl1qzoXqLQq+5fZGIFRyyY8wFW1uiNu9k=";
- s[129] = "YXmCWhiNz4/IhyxQIYjgNvjX+XwDiPTSBMaFELm5X8Y4knGRnkF4/zix8l9wHBb+7Cgfrr46rF7eiIzaAFLjLjjewy63duBJiVbEWjqFO0fu6T9iIjuEaF2sTppvuZNPHx80vN+HLAnAVmgFESw5APXWn15dizvuUfVHd5isCqbA";
- s[130] = "GJfUoBivW5uqDpUxTRfjGWNYfN3/dTFtdRqCIH5L2c1nWX0dgY3ba1+fW/YX1Oh5aw4lC6BIiiThjJoV1VrNnlXzbcUcMy+GsDUUB8Qe8lBvfe/t4RmNPB0hVgrS89ntbuU0SsCmWw+9DqM3nidPebANKERig1zZTBBKgpVf7HPFCA==";
- s[131] = "eTerNs7dOqJAxAxcMQRnUDc2cBj2x0jU1g1D3G+b22kDz7JBzOy/mxhGXAQ3130lavWMhImSBkReU+z0A13EYVMUv9PFzD747KCvns+SCo52YNHB0896b4l47q8hu8jsD17TZ2uWWJhS4cNnSE1jeM6NoXGKvf90yxfzwucNYc4RdaQ=";
- s[132] = "lbrGsjbzE521q8tzVHV7vcTPchUnzI/UfeR2R+cmOa29YljPWLht9Wx2JrjiKv4Of5nXe7kvhi+LYUuFVqgaqIFhC/PLbqOFiT2VZcXorToaRT9CLiqV5b6nHN/Txz6SI7MiD3hnk7psDbglPOo+ytqc9sFHj7UkR1ZctQjwFYwJjlxf";
- s[133] = "mQwAPzYzfxz9FXEiZ6M8u1oN3EJbFYmNVfpm+j0DqgU+OPI4URHBIrF4xvdMvAPn0WuarbQy/ZVN0eKL7S4K3Mvan0flAwaZdI+e5HpkfxOoGTp8Dk5EFTXjmZ/s+GonePEQEGNVPL1WYoD6xXqAAvMLKtyrFcpoiGS9eDBlsZDQzPzz/g==";
- s[134] = "3G6d12UY4l5W7Nnw0BL0HnViVg9SdEuLMqeZwy0RlJR/Ytcgd/mIxIuXXAlGhvhoX6Xc2BGU7RpTi1jYKzA86yul0j96dbcE4OtrP9lUBJlcY9eWz59dvLqKxwt3cEOBwrPf69MHuIa256es3AOCobfC8RQScW0PQ0QUa1VHB/eXSsVTSWg=";
- s[135] = "AxgrZKTFk5JvLC3DBACHwp266FxKI/yn9F+1tYkzL57RVs5HCJYS47VuG0T0E2wqzHqcLKPQMZWU7vbRoyMGNL3ZtaHoZqTqcq9KWtODC+OnEvSS7+1P4SmQDuyL2MJ/eJABJKNcu1K/Lk0buAaO0FvX6OGBcPzu1+dv/ZkwuORK07qRnxqQ";
- s[136] = "atkG8l2U/Nnm+zLu7zjenrfcAVQJMUqHimFZ3cQfaUp4qyrFn1UiwZ33j66Vt63eVaT/FXx+LlEnsHn6ATPBMp3iEYoBJYyNpjz/zROhBbcznQAMdWUTcyKInvnG3x6ExgBXpyqfxxp/Pm8by7LlSUT5MKHdcu+TEfUXRokCr2iPnt7NYsNDfA==";
- s[137] = "dciU1mSHGcBxOAVBgJx75J6DaQdBZfTIzQ04WhkkdRMupOZWSnv19xhz8hiO+ZnbBtDJuO5rHsUGzH/jYacfZyCQ924roRvkh3T1yxsLq3abZJUCD9HYnPTELVhv1+cEF4aoO3vGOu2FpfLUn5QTd0PozsIqcqZVB2V57B7DjfizUe3D8Yf5Vco=";
- s[138] = "dgR1PPacBvtILBmg33s9KWtuc67ndh3rCHZ/lIN7sENgbFqJQy5DC3XIeHTV7oWd+tJQaXxoC71/SU7Rz6OClAMKXLbMz8U6RPiqn3M7MRCQcDfNjA5cCNknXT9Ehz/IZF/7lcWrwxBKYm4B98lPkpZtR2QHndiQ3venzWrP0P5y27mReaFuaJ++";
- s[139] = "1Q8rfp1HuGsxurTgGMakxj5SwNF7EixXxVPnfGADWDcygh5C1BMXqiL1AuVXOVFOsaydfLWGC8Kbh/JiL6H+12lYrNGUT9yJRIzRDi4XylMnrYwBtwCJjoHSi4exz5K2ih54utVAuzXZg6mnc9ied/mNRjj9d2HFD5mv0w/qTN/WFxEmtuZM/nMMag==";
- s[140] = "w01TnPP/F3Vni3fBdV32Bnbb4J1FcbaE+Xn44no5ug77U8FS1gSm3LqJ8yTyXduzl5v2dwBEfziEfTuyqgeLLsCYTBjXmYOIHQosEl6DyAknu4XK52eQW+Fes9eSs2Nq+G4aaR4y4leeFNmCoZ9BQmAAZr0LFkqnvqaKmBVgcgxPs7/8SQHnpqvaU6Y=";
- s[141] = "OfzIF38Tp5g1W5eVbrkrMe0Mm7e0wBYg5hVvLpn/5MW5OFcmRDuBp15ayRBnJ1sBI93+CNl0LwP8Q0z9IXFjTER5gHZ1KfG8NV+oacKNG7aYrbUftkSL/oPfRNPez6U0FuWgvVrXUB6cwKTWvwb9KoD7s6AGYRdH50ZgJdBniFD7dKoOQnJ/ECuTUXI+";
- s[142] = "4hoX0sjqlkSJPUq627iJkNYRbtD+V2qErCuTikaeRDEZvVHWvzdvwj4W1xxJjz+yHAN6z2EjCWidcSsVgTejQ1bH8uTzJgh/zq3yGUSsJoJWrecqxsge8bEBjkm+qUO8G3kAnC6FMjJ2NYQeXf6OK6OgsqyJwlHPTyAms2/IoYTB4iEqgIFG/2fNEJEIag==";
- s[143] = "M/dy14xNbZMRfHiKKFdmD/OrEB+8MexrRO8mMh0i5LrNA5WUtLXdwUfAysYmal94MSoNJfgmwGCoqNwlWZBW1kpQaPdqsrn2cvc6JcZW9FlOx07DERJGbZ6l6ofbzZWgF+yf+hvT6jnJvXBVCTT3lfO3qo4leNuEJwsuU6erXGC3Ch53uPtGIrdDUpcX6/U=";
- s[144] = "GgLr2hd3nK64IZv0JksKAT/yJNQ38ayuWyBnWLjXbEmT048UDppsrrnP6hikRo5v2TlHGhD2dcwG9NLK3Ph8IoIo9Wf2vZWBB+SMI9FpgZxBWLEjwHbOWsHaEQMVsQfk38EWQP0Fr6VyMKlEQfpsRkuCpp1KxscaxK7g5BgXUlb0a2x0F+C9hEB0OVPsj4JN";
- s[145] = "W9lKcLDqNGQAG/sKQNaRmeOUmLJ7GcMNqBaGZ659Rnjr6RTrfnmkp5Z9meALnwXoHjPjzSQDJnVYsY+xyMnuPgl6gMVAhAm+XprYVpsne4vt+7ojUqavVPBqLy5dtnhp1qfcnAiV5cZhHXX7NbxkUOzptjEGCQjnhSH4rPbZtgoIWE8Z6boF3l/thLnFX+AiiQ==";
- s[146] = "iYLn5h9lIhD/x9moaPRnTX6mJEJKThg4WXxS7IrR2zblH26uOkINz0dJNTJVets0ZNYDnsnT7J2iI3Y6hTVWPGoYU49J3B2LhCREs0DZQ3C7080FtiOcfHbfBLNn0DyCK1LeAC7YB/bNdiyhLqH8fKl+0+KhiPDIUBJY2e7IbZR/9t0sxJbIXx6cRvI5AXex12o=";
- s[147] = "SlRJEc7npTUvQq8SgBYKmVY/3wHYp2gsDxafN/JLUuEqEjmWMtW7fxASi+ePX4gmJJqLhD5t+AZxiCwYK3L3ceuJx4TiqVgJz8d6sc7fgWXluh1K+BcGPbZ7+Cq4Vsga7JEBVekviEZ5Ah4apNr8RkB7oMOUVPGxRcyyaVE4zBW+scA6c1yi/HQXddQ9rWyLUsVo";
- s[148] = "AAlbGR6ekLOzx4hpqZTUqVUQ0FL2CFpgCMOp6CuuUzkSnWXpUjvOiSDkNPgoTPgpgmg3uYvMsX43mkPGUGC9awDThXyGQh6u3WfWtmhiPRqXnjFek+EPd0LYXps71non6C9m7nUlYNWzBJ1YzrzWjlB5LLPBN8bsZG6RbdZkYMxJ9J5ta/c30m8wDDNuTm0nEE0ZVQ==";
- s[149] = "nWWbBhzObqwEFh/TiKREcsqLYbRjIcZflJpol16Mi4YDL6EZri22qRnTgrBtIY+HieTYWuLaCSk/B9WcYujoS6Jb5dyg3FQ6XF9bYaNQGx2w8DHgx0k2nqH/0U1sAU0kft32aD2orqCMIprbO1WJIt2auRnvcOTFoOax926nAkxvR3nrFVDevFjDbugpWHkGwic6G7o=";
- s[150] = "WNk1Rn2qtG+gk0AEewrgo+aRbNrG4CgQpOR8Uo7c2m2XQY8MVDu4uRA6rzYGGdgqTcICKky9MvHeJeNWVAXOxmA4EdXQ2xItFJdQtxBt56cad9FBXXsz21yVsPr5d453abi7T3XfHVTToekiOlxAJs+bpat9cFRbIdHghO9wc/ucoArT53vpYsnyeVnmZG2PX48lXpNS";
- s[151] = "wVmiO6mdf2aahrJlcmnBD0Qa58y8AvzXtJ54ImxgPLPn0NCQIrmUxzNZNTODE3WO6kZMECaT/REqT3PoOBp9stCHCFNXOM7979J44C1ZRU0yPCha00kQZBF5EmcLitVCz10tP8gG1fiIvMjwpd2ZTOaY4/g4NeJHLjJPll0c5nbH7n4v+1I+xG7/7k7G6N8sp21pbgpTYA==";
- s[152] = "OoiVZosI+KG0EZTu+WpH7kKISxmO1zRYaSPMBMW0AyRiC2iZVEkOMiKn12XPqIDSW/kVA58cvv/ysTAzKLTu78Uo+sVcJe3AtLdgeA9vORFELTP4v9DQ/mAmehe3N8xk+VTLY6xHWi6f4j9cTDW/BDyJSDRY00oYoHlvnjgHo4CHBo0sMGgX3CwcnK2hpMFVtB/3qPl6v2w=";
- s[153] = "97ZVsTYwD8VrgN1FOIRZ8jm8OMgrxG3o1aJoYtPVWXp9cjjlgXqTMZVsoWr3pr7pudw+LYo1Ejz3JpiUPHqWcZ2PWrWs7PR1akYGuwdCBHYvCGTcZYFe/yu1AB8w5zYsl1eJR45g0u1DlXfx5BUAUzc4yJDjc48Ls62bn8t0EJ7+30sWwifqKuz2EHpsqp1j/iMlwzKJGjGE";
- s[154] = "0NSYKTvBKKInwL9PJ/pWUWVX4gjF3igsA2qqQMsRew0lI1LcCB18eGCYk0AnyUCe99w5lWHGFUMMeH6DZciAylWGeDn19JdzVOTevBWk3LIujI1GvsEB3oVqf2Zl9IZeDGCT4+bQKBWvgcXHjysZfnn/5z9Xz06qrPqac5LfS36fDcwnkrUYQWDsL2Ike32ALmOnkcDjNq1BoA==";
- s[155] = "5ok+rYI4LCgGa2psGUN/fdkT2gQEToB9HRiFXQpe2YcQvEN2z7YlJCETx4jSWw06p5Y8tZcp08moKNYwUJ40DvPpGlDG+wUpFhC4kkfo6vj6TrCj5yoWJi5D+qdgH2T0JeWM80cYN0bsOsetdaqNhDONlYXZ2lVYkyVS/wzw8K5xX87EWktwOwFq/yYhuWCYJ9GZL7QuDipJjEE=";
- s[156] = "KHzTalU9wPSnIjh5g0eHi1HUaFufxJpXpjDe0N3wEKINqbgzhbj3Kf4qWjb2d1A+0Mlu9tYF/kA9ONjda5jYfRgCHm5mUrjU0TAyT7EQFZ2u6WFK/sFHP++ycJQk8k7KLPUWA5OWScy1EO+dYF4d0r6K5O+7H/rpknxN6M9FlP8sH83DXK1Sd+UXL32D+4flF580FaZ5B3Tkx3dH";
- s[157] = "RrJVxIKoDXtCviWMv/SXMO42Dn6UWOKDy2hh2ASXssT0e+G6m7F1230iJWlEN0wBR8p+BlTdBhQrn25098P3K16rBmZpzw/5dmesIJxhYPaM4GiaOgztFjuScTgkmV0Jl/vZ9eCXdEVNISeXkIixM4pssTFuUV7PY/Upzdj55rDKGLr1eT7AFVSNP30PhL8zZs8MANqKBeKBBDvtww==";
- s[158] = "sy4t5rFA75GRBE+Dqa9sQxjPluKt/JnEY54guHnKqccmx3HGiyJ0jUA+et4XO8Xg69wCA9xVxJZQL73z80mVfIf43HIKOxgxT2IjG7EKMOD/qx6NnMTve4BryggLtbLQUeRfhriQeY7h65tD9ierhccXoXDpGnmBn9m2BQP78y+Qhc4eIsa3LcxbQJUIwvURjFp/rgMD7lhOLboa/2Y=";
- s[159] = "Zs/BfFoWImYau2dZLb7JneeTQp7sQ06yonEq0Ya4BNOJGy/5dGH42ozt0PpP2IZ/S58X7esVgc6jA1y3Bcxj3MPoDjQJSZHFEtR3G31T8eF5OpPVC4dw9s9clllM05tvcemssLdcd85UP/xBaDrmpAl8ZDSc73zflK3nJw8e0HQFYntNnlZPFyyyBLHnLycb6Jlvq7F2OqrZR+FXZnL3";
- s[160] = "hdeDJuRnmb8q9EYec8+futT/CvqhpqoUdtmG6E31RrYJDs96M5Wfng90IEqrncZe4rVYDocRZK23dvqtJaPhTUBXXh42IyMlUnro69KI+075FvYYwgVaUd10r7ExWM5Z7DCQ2x8Tm1meK2YCTPkF1VXXexl1UjYCnRQuQxppdophMwroJK8VqlJbFFslchTSBFuI7wgcdy+f/LHMbMsusQ==";
- s[161] = "ClCCOv0mD9//LR0OisHfamxcTvmlwMLgAIQt3hbOjRPkXwEgaDzP0u6LN8BNwdOVw+LhrbzMI8zQzHvo7mGPkQICeeim/x+xmGPQtmWnXxCWiL1uf/8eR5Wuy9Er8skTB8rG4/ubb2ssvCkubObPAkMSOgFnX9UtxnCN4+nMNV2vvn4xMTSvvQyYWewfnlNkflTyva1epE9RVW2RqRtJikY=";
- s[162] = "Fs+AmFCnUr/imw8D0GpNidIP9qwW8yRAzmtqPS+vT6n5U4YFQcpgbznrYO4TPqkVF2oz1mpgLYIgx/u2XsrtljGX46LfY8OyUPaw4/da38QGngoIlS2cN01cgN3efSjMlnZFo1x8T9p0Nn1IgRgevOd5ezVUL7WdY7eeiE1pXXcGBgDYn7NDQph0dC6HDlBiS95bDFcZ+6FYigE4WybpsOHL";
- s[163] = "wgO4DdGZy9g13IuOhkJGJcToyLuCBVm9T/c8qY4NOheVU1NW2g8sPIo+RiEsSST8sx6+Jh/A/kaCxYvJ9CsgnBjZMMWRsd383HZAoJtkxwKvyoeXzzD+puFvqKQBEKrlBEwffXhLDoFQAW2ycYtBGztl0GsUtoOob2nv7ienx1xD6KNZNaxYx2ObRAYS/e8LS3pg5dku9MPBp1X12m8ZIXRAaw==";
- s[164] = "EkXt02SaRUIjFmoLxyO6N+giL4iA4fY0Exao+mjgEfZ+Wv6w95GXHBI1xlYMVLkOcnu9nescvcXQH0OrqL9uforEUTGTSg2ci67m4GrwAryMy+5eUo77Q5GpWKfsg8nDbD8a3gUI/9EE0sCNp7tMaKwoJ56cxhbG3TJYpqWTpq3/S3q76x+3ETL+zxh6EMh8MJPfWcIxlDS7evKqdPgS00KgUtk=";
- s[165] = "OuBqx5LFJroRbDn41+4azFHlKgw6bMgbsRGaK9UnPvi5xfmV4SLQ2YzIhopGi1F57L6vKukaW0XlFk/Ff5Td5IMC7U+kvXKlf8fGIIQ8FaHI0vbIX89OJlBqlICqftSNiVRxtaE+aCh0rBoDfgPwuC8qBC20I1O3ZLuKfeUVGkMOLEWeZLS6mmcn3cSERj9o/dEl8QYwQvhH+VG6YWF//yki1Vu8";
- s[166] = "SO/vDsqZDdImOdH19sZI7FUVhlx1EI0XRr8ArTuAG5F8LDK76Bct2C7fXTUowilXnJWhQxvbGiulkUGSuVjVP12zac9bShRpr1L3ucde7n1f9y/NcHJCwdqTLq7RYygItQ4ppQGiP9jXf2Dn/qmVZZTh+SY3AZCIS+OVo2LAiYJHWnzzoX8Zt+dOYiOA/ZQKZieVJlc8ks+2xqYPD55eH0btZn5hzA==";
- s[167] = "tZL/qACMO9SzmgJhWQMsbKgE5lPAEbxn3NR7504ilgArR8j7uv1KF46uQyjrkEnyBormYB/6nLGlHht62IQftMYf5gHpHFfTvukRKF8728yIYAAYHPQ/WjHzHdVSqUJqF2a8RE6SvvY+KSKWLMU3hjn1f6dqX599hYD7AnbPGTpFKDU5sLFOXbuynU1sPUhP+a4Hev9yNU6atLDo4CkX/Yq3FbpWVuQ=";
- s[168] = "GRe7uF1wH5/71B3vmGF+pN3H9PKO1tLwsnb0D4/Pm7Pu5KAe4OfelkfFIBgyjuoZrpeEkGZnb+qf+Kn7Kt1hDwYr/Mb9ewuwOXsbIpLQMgfh0I5XsPrWocduVzn+u/cm3cr0Z11zsx0AZjTqvslACkDqiquY41JhtGdc22RCvIYom2l+zzMIMyCPsHeCSB1MBu8EWK3iP7SD3dWttwzMg0xanoPDgk0U";
- s[169] = "8BDFu+29lptlGSjcZe7ghWaUgIzbuUpM5XDFbtJVQPEd3bAE0cGRlQE9EhKXi5J/IskYNrQ357tBhA+UNDNXCibT2AZGpzWAcwE6dP+14FuRL5Gxqh/teuPYKr5IIn7M3SbgOychZzLI7HGCvVhBUiJBu8orI3WmAIVcUhAsMGHsFveck/ZCXQA+Uq/WVnW1VNs6hSmIhsAFc51qsmsQK07z2Wptx4rRjw==";
- s[170] = "siPSXD4u36WYtTvvDzRlFPiuZMnRczrL3eA15955JDCc6/V2Cvu6m/HPO6JxogxO0aYTZ5tejYDOIZgBy40DgUZMqPJ2IpYjsmUbjjJU8u/OpwhMon525m3v0EYlvyj2Qp3pwFKDkvncK3aNjN3KaaX6HuIy6kyqsDl0BTEnB5iJyHLRBCkeznTK019u48Yfsrz2oGuZcWzNj5/vKMdxQPiyJ9EHyox8Ark=";
- s[171] = "+/14PnFQVZ7BTHKUvkTtRrYS7WnPND5gZ5byMhUrDLkJa6UPBV7z0nrDMifEo/dQfUq3EjCiG6xGVhrUvAzgxqOQZTW1Y9p9M0KWW+E0XvCQppHFpuMqF1vYsF0OD6AMiE9JtGnWs3JcaWP/XBF/CvhQlFGbHi3fbrD/haTEBnmpJWBgMdKribdbXHtBSFZ2MzCX2eDtxoDdRdEVGs4v/q8gVBS+WsnZ3TTF";
- s[172] = "31I1ja+B+aopKkztGzJYvJEWAshyoAAV5yve4LnP0kdImUQaVETSuo5CDIYr7zM8MCD1eYPpLicmGnA+C927o9QGAVL3ctO/DCWhNinW7NmeYIM+o4diKBkDPjHmSWa+nq4nr+gOap4CtwL2wW2B5Yqt26pKgN9uAU5CmTL26hYFgMEOZfrkQ7XdYGy2CN8RJLmjeSFVVNBG/FTaK7tpuy0LQSkko6wczBYGeg==";
- s[173] = "XbRfDqGe3eeI1tHx8UnPneDB57N8VeSSzXzVCNSgxOEfd6d/un5CDxHG+m4w3tIbtSky4R2+zMF+S5cRvTOwZ/veegYtLKTxA0mVedWLFkfh/v4NgPJ+NEU+cylbSSZLAeBofDvoJwnYKujN2KFa8PGAxr3Y8ry3qdkS8Ob1ZiHYAmLvKS9sGb/vjTvRy+a4Q7kOepsm7PYisinKelBAvDnjli6/lOutGrenjX4=";
- s[174] = "jGEj/AaBefac9uOcmGuO9nH+N+zMsC4qAe6ZUEMMIXdTGnSWl7Xt0/nKqyOj3ZH249HwkJ8bn5C+0bzOpQ1eA3PxEq6RfKMrjHJPJmTZXrSESTjfj3oNLU/CqqDOqd8znTgN6nvnUdCeStLMh9bmWF1+0G11nDwg6GQWWQ0zjVDTq5j7ocXcFOyUcu0cyl5YDcUP0i2mA2JullInU2uBte7nToeSGB3FJxKueBbv";
- s[175] = "RAzNCxlP2S/8LfbGtlSDShox8cSgmJMOc2xPFs8egZVJiwlmnS3aBWKPRbbxkZiVVYlu4GNJNwbocc6dgrl28HXAsYikE5wwoQ1MeOJWU3zzFiYENh7SLBQfjVPQHucctr8P6Rl7YL5wHc+aC+m92R3bnzm5rp1PeHm7uzy2iUUN0cgfbwJ4FrpXhVMTsAUpTbg1+037EWcGOuxir4dG2xBfgOwa+ejFHkw7y0LWRw==";
- s[176] = "08hmZptBGKKqR6Qz9GNc2Wk1etgU/KogbiPQmAh5IXlTBc97DuEToL4Bb889nfObVQ/WelmiCS8wEjSBdmnlkkU7/b5UT3P4k1pB6ZxPH9Qldj5aazkA/yCb0kzDfJlcdFOh1eAcu5LvwTXOizmPwsDvJEnOkaDZrKESZshsHU2A6Mx6awk9/orf6iBlJHQIIH3l4o3b1gx2TNb/hUgdAlwtQDhvKO3skB0PS+rcWAw=";
- s[177] = "0GhrgbSSHPLWtyS2mnSxrNAj/dyrFQcxIgPjT7+78SZ1ZTGc03vsmlZ4Z/bOO84E9yKblaI5dSHVXrx57L0kikL8tgKCsAkUNO3l/4zv5FfCrRTgGx4sFTFB1NNcLcwagkvFzde764DjYmj4YZhYsXSZCVKi0uu5M8fpgGDZ9UMSFR008cbhaIoFLWSANqiNJYSvTQZhGWfLtIPGLN+gIOMcaKhx1b5vg6OYSz6ScAM/";
- s[178] = "2VGiMV/f2hNZAjw3fdeHx/wRIVzeP018lZynzwSySG/zQBxyRmi3YmKVZmh3aJunuiqmvdt0kJ6lX7M8BajYHPCBkqJOx8oPJ/K1oADxVgnavZ69dKYrSy9/Pm6sHxjFrdSz9TelUK9sgoFTWS6GxgzWEqXRBDDpGUnsNbSEcWLPKVLNNoYAcltY98JZaNSZBXcpa9FeSN7sVU43q2IEcDx3ZkJzRJpl/lb7n+ivMwX/OQ==";
- s[179] = "iMSCh1m5vct3C7LEn5wKRYtalzvG6pKahG19rTb6Z9q7+buDsML5yM6NqDvoVxt3Dv7KRwdS3xG/Pyb7bJGvQ2a4FhRnTa4HvPvl3cpJdMgCCvsXeXXoML4pHzFlpP0bNsMoupmhQ0khAW51PAr4B165u1y5ULpruxE+dGx/HJUQyMfGhOSZ5jDKKxD5TNYQkDEY28Xqln6Fj8duzQLzMIgSoD8KGZKD8jm6/f8Vwvf43NE=";
- s[180] = "hN4+x/sK9FRZn5llaw7/XDGwht3BcIxAFP4JoGqVQCw8c5IOlSqKEOViYss1mnvko6kVrc2iMEA8h8RssJ4dJBpFDZ/bkehCyhQmWpspZtAvRN59mj6nx0SBglYGccPyrn3e0uvvGJ5nYmjTA7gqB0Y+FFGAYwgAO345ipxTrMFsnJ8a913GzpobJdcHiw5hfqYK2iqo8STzVljaGMc5WSzP69vFDTHSS39YSfbE890TPBgm";
+ /* Here are the randomly generated byte[] arrays we generated to exercise commons-codec-1.3.jar */
+ private static void initBYTES() {
+ final byte[][] b = BYTES;
+ b[0] = new byte[]{};
+ b[1] = new byte[]{-72};
+ b[2] = new byte[]{-49, -36};
+ b[3] = new byte[]{77, 15, -103};
+ b[4] = new byte[]{110, 24, -44, 96};
+ b[5] = new byte[]{-43, -61, -67, -75, -33};
+ b[6] = new byte[]{-80, -52, 71, -96, -105, -7};
+ b[7] = new byte[]{-115, 7, 15, -108, 59, 25, -49};
+ b[8] = new byte[]{76, 6, -113, -99, -11, -65, 9, -123};
+ b[9] = new byte[]{113, 116, -39, -69, 12, -41, 60, -29, 82};
+ b[10] = new byte[]{46, -39, -1, 101, 53, 120, 34, 52, -6, 56};
+ b[11] = new byte[]{-23, -8, 126, -115, -43, 55, -43, 35, -90, 90, -73};
+ b[12] = new byte[]{19, -2, 76, -96, 62, 42, 10, -16, -18, 77, -63, 64};
+ b[13] = new byte[]{-38, 127, 88, -55, -16, -116, -56, -59, -34, -103, -69, 108, -79};
+ b[14] = new byte[]{-88, 25, 26, -36, 26, -70, 87, 125, 71, -103, -55, -121, -114, 70};
+ b[15] = new byte[]{90, -4, -103, 123, -87, 16, -14, -100, -69, -101, 110, 110, 113, -84, 9};
+ b[16] = new byte[]{-95, -118, 113, 51, 46, -127, 74, -106, 87, -123, 90, 78, 71, -89, 87, -104};
+ b[63] = new byte[]{-55, -20, 69, 104, -46, -102, 63, -27, 100, 87, 1, 20, -65, 20, 23, 108, 45, 7, 72, 40, -65, -78, -77, -104, -19, -51, 55, -22, 84, -10, -27, -6, -20, -29, 24, -56, -66, -99, -75, -32, -111, -62, -125, -77, -117, -3, 118, 86, -36, -125, 30, -24, 32, -32, 72, -64, -102, 104, -113, 117, 121, 24, 12};
+ b[64] = new byte[]{-66, 74, -96, -98, -30, 119, -90, 92, 77, -74, -117, -34, -120, -62, 110, 96, -77, 122, -63, -108, 11, -91, -67, -59, -125, -113, 63, -52, 121, 29, 22, -32, -18, 114, -29, 10, 89, 84, 78, -2, 120, -123, 70, 2, -84, 22, -89, 49, -85, -91, 96, 11, 28, 16, 109, -29, -30, 63, -37, 17, -97, 28, -5, -62};
+ b[65] = new byte[]{96, 121, 44, -36, 96, -101, -38, -27, 69, -29, -74, 54, -76, 40, -98, -120, 49, -119, -13, -65, 81, -101, -105, 65, -123, 8, 80, -117, 54, 33, 125, 99, -88, -8, 26, -63, -37, -14, -66, 19, -68, 25, 89, 56, -99, -41, -119, 76, -92, -50, -76, -5, -112, -76, 55, -46, 77, 40, 7, 1, 17, 39, -86, 101, -110};
+ b[66] = new byte[]{-49, -50, 121, -42, 57, -112, -89, -12, 44, -9, -101, 112, -37, 110, -66, 28, 33, -42, -82, -30, -79, -4, -101, -33, 4, 39, -48, -26, -99, 31, 23, -66, -26, -111, 42, 105, -21, -95, 57, -25, 104, -92, -38, 12, -100, -84, 16, 108, 48, 47, -51, 111, 57, -64, -127, 54, 104, 51, 54, 113, 122, 23, -55, -62, -18, 61};
+ b[67] = new byte[]{86, -60, 118, -62, 26, -86, -2, -92, 38, -33, -115, -66, 76, -36, -11, -106, 3, -103, 50, -123, -101, -92, 44, -2, -110, 61, -77, 126, 90, -76, -97, 30, -46, -3, 23, -124, 84, -11, 9, 114, -88, 12, -75, 92, -21, -81, 97, 85, 64, -9, -63, 0, 126, 85, 70, 52, 126, -122, 76, 112, -65, -122, -20, -79, 9, -84, -15};
+ b[68] = new byte[]{-25, 25, -120, -89, -57, 84, 37, -100, -28, -118, -62, 36, -72, 67, -20, -100, -11, -17, -52, 55, -116, -93, -113, 42, 88, 87, -57, 34, 125, -102, -65, 120, -21, -26, -86, 25, 28, 43, 52, 45, -13, 68, -55, -22, 66, -34, -3, -84, 107, 73, -62, 83, 65, 101, -86, -55, -125, -55, 50, 57, -1, 104, -19, -25, 59, 11, -75, 93};
+ b[69] = new byte[]{-76, 97, 32, 94, 56, 37, 80, 31, 77, 108, 43, 98, 75, -49, 0, 122, -46, -19, 70, -88, 66, 2, 120, 115, 57, 66, -107, -126, -10, -55, 100, 122, -114, 3, -84, 124, -72, -22, 43, 3, 91, 119, 53, -58, -120, 3, 77, 25, -87, -77, -40, 0, -69, -72, 47, 50, 38, -30, 46, 37, 0, -65, 80, -126, 33, -1, 38, 14, -37};
+ b[70] = new byte[]{-128, 91, 113, 18, 22, 9, 106, 16, -26, 83, -105, 105, -71, -42, 44, -23, -108, -20, -88, 12, 126, -77, 104, -2, -45, -96, 52, -51, -20, -101, -35, 78, -25, -123, -111, 108, 110, 64, -125, -107, -37, 52, 17, -123, 40, -87, -22, -39, -87, -109, -26, -20, 94, -126, 12, -29, -125, -35, -43, 59, -99, -119, -98, -108, 77, 3, -57, 35, 14, -12};
+ b[71] = new byte[]{-113, -8, 127, -44, -100, -96, 96, 14, 91, -114, -37, 113, -51, 12, 107, -26, 0, 109, -126, 31, -128, 97, 90, 51, -124, 94, 22, -126, -9, 20, -2, 14, 61, -65, 72, 84, -53, -95, 93, -123, -10, 94, -64, 98, -66, 62, 27, 115, -113, -76, 90, 108, -114, 105, -37, 53, -14, -50, -7, 38, 45, 7, 69, -123, -46, 57, 82, 110, 14, -26, -52};
+ b[72] = new byte[]{-101, -23, 24, 84, 106, 35, 33, 30, 105, -127, -68, -5, -92, 98, 102, -38, 15, -73, -86, -87, 59, 126, 25, 119, 114, -116, 26, -39, -27, 107, -122, 72, -69, 90, -121, -14, -53, 9, -47, 123, 58, -109, -60, -23, 1, -127, 81, 115, -22, 114, -84, -14, -84, 105, 109, -74, -13, 0, -73, 45, 112, -9, -116, -78, -97, 93, -91, 117, 31, -71, 66, 107};
+ b[73] = new byte[]{-92, -10, -122, -100, -54, -12, 81, -119, -91, 118, 114, 85, -109, -15, 126, -35, 96, -119, 39, 90, -10, -94, -37, -61, -28, -94, 93, -73, 107, -75, 70, 116, -70, 47, 8, 71, -121, 2, -62, -87, -11, -68, 59, -12, 4, -125, -115, -42, 119, 18, -88, -104, 98, -1, 36, -51, -9, -74, 127, -63, -10, -109, 15, -96, -123, 52, 65, 49, -93, -85, 97, -111, -93};
+ b[74] = new byte[]{-104, -20, 115, 27, 44, -90, -23, 63, -63, -60, 37, 121, -99, 40, -120, 96, -55, 95, 1, 73, -126, 55, -72, 45, -17, -26, 83, 50, 13, 100, 119, -61, -19, -118, -71, 62, 36, 94, 93, -109, -59, 18, 109, 96, 110, -1, -42, 111, 54, 14, 89, -70, 34, 66, 120, 108, 31, 105, 90, 106, -91, -99, -54, -9, 36, -123, -20, 47, 59, 38, -5, -75, 69, 65};
+ b[75] = new byte[]{85, -126, -50, 32, 78, 3, -98, 28, 73, -97, 113, 74, 75, -3, -111, 28, 113, -40, 46, 86, 98, 25, 87, 85, -2, 78, 46, 5, -69, 64, 96, 117, 18, 78, -108, 115, 105, -90, 15, 24, -48, 21, -115, -45, 112, 109, 49, -56, -118, 25, -98, -70, 79, -7, 97, 5, 50, -16, -47, 108, -60, -118, 38, -8, -72, -69, 110, 117, -94, 6, -127, -54, 4, -13, -5};
+ b[76] = new byte[]{-19, -6, 12, -92, -99, 19, -110, 112, -102, -74, 53, 34, 75, 27, 103, -72, -92, -94, -49, -124, 47, -105, -8, -99, 89, -113, 84, 42, 36, -27, -114, -124, 7, 103, -32, -68, 109, -59, 44, 114, 114, 63, 109, -102, -11, -35, -18, -128, -65, 37, 33, -29, -77, 37, -91, -47, -81, -52, -119, -76, -26, -91, 29, 49, 101, -117, -95, -110, 78, 104, 102, 47, 14, 107, -21, 89};
+ b[77] = new byte[]{-113, 20, 18, 26, 33, 108, -7, -67, 83, 124, 78, 37, 13, 64, 15, 80, -14, 116, 73, 103, -108, -126, 93, 55, -84, -82, -102, -70, 39, -106, 37, -58, -85, 12, -127, -52, -9, -72, 6, 56, 115, 38, -56, 123, -99, 68, -54, -92, 102, 98, 36, -59, -124, 96, 98, 0, -126, 82, 15, -55, 121, 79, 117, 57, -112, -9, -76, -66, 20, -5, 3, 97, 74, 28, -80, 123, -49};
+ b[78] = new byte[]{80, 105, -121, -2, 9, 123, -73, 112, -28, -13, 77, 111, 70, 20, 67, 17, -72, 44, 125, 40, 109, 29, -99, 96, 101, 9, -8, 40, -42, 121, 66, -52, 55, 90, 33, -93, 91, 66, 38, 34, 117, 71, 107, -30, -46, 28, 28, -53, 82, 60, 2, -47, -99, -25, 92, -18, 34, -29, -32, -94, 41, -118, -128, -78, -109, -107, -120, 78, -106, -87, 85, 24, -15, -108, -107, -48, -24, 56};
+ b[79] = new byte[]{-63, -47, 40, 98, 98, 110, 70, 120, 54, -49, 98, 36, 2, 36, -96, 39, 80, -106, -39, 81, 59, 31, -70, 23, -91, -123, -124, 20, 83, -68, -100, 109, 27, 102, 126, -49, 30, 20, -4, 43, 40, 90, 59, 106, -30, 118, 95, 30, 80, 76, -84, -115, -83, 21, 92, 80, -14, 66, -92, -96, 102, 123, -35, 80, -86, -62, 25, -22, 86, 25, -106, -16, -45, -3, 27, 15, 11, 55, 2};
+ b[80] = new byte[]{-26, 70, 106, -126, -75, 27, -73, -22, -51, -28, 21, -128, 117, -41, -108, -74, 111, 83, 25, 62, 55, -67, -118, 65, -24, -9, -78, 67, 4, -14, -53, -43, 91, -81, 79, -108, -1, -124, 51, -53, 66, 48, -33, -76, 90, -37, -35, -57, -102, 73, -87, -127, 12, -18, 73, -59, 105, 112, -120, -123, 25, 115, -64, 21, 108, 19, -95, 31, -101, -94, -4, 46, -19, -91, -29, -117, -15, 103, 51, 9};
+ b[81] = new byte[]{19, -114, -69, 48, -55, -119, 110, 108, 47, -16, -23, -100, -39, 55, 92, -56, -54, -1, -33, 64, 124, -117, 53, -101, 127, -32, -128, -72, -101, 112, -21, -74, -11, -125, -37, 107, -124, 46, -89, -32, 102, 39, 94, 55, -106, -12, 54, 47, -103, 106, 8, 36, -4, 116, -50, -11, 63, 67, -24, 42, -65, 71, 45, 122, 13, -101, -57, -45, -10, -102, -72, 12, 12, 4, 91, -23, -24, 40, -62, -88, -15};
+ b[82] = new byte[]{86, -101, 124, -123, -122, -8, -113, 29, 69, -5, -76, 68, 95, -78, -70, -26, -2, -98, 59, -111, 117, 24, 56, 63, 43, -60, -107, 45, 96, -46, -89, 75, 43, -70, -106, 4, 66, 64, 85, 71, 25, -63, -11, -39, -95, 74, -113, 87, 30, -100, -8, 11, -54, 81, -105, -54, -4, -39, -4, 87, 102, -23, -90, 17, -2, 20, -40, -24, 116, 14, 42, 121, -82, 115, 109, 12, -65, -120, 38, -14, -4, -107};
+ b[121] = new byte[]{-123, -2, -67, -58, -65, 102, -76, 87, -8, 55, 120, -10, -72, 15, 76, -128, -78, -7, 103, 47, 120, 30, 59, -2, 85, 8, -67, -29, -30, -46, -13, -34, -10, 36, -104, 3, 28, 36, 14, -64, -2, 112, -123, -44, 36, 87, -28, -119, -91, 121, 34, -56, 113, -102, 74, -60, 56, 126, 23, -87, 63, 12, -18, 101, -63, 41, 96, 68, 126, 109, -23, -14, -42, 63, -116, -48, 116, -103, 123, 126, -116, 117, 18, 33, -107, 58, -89, -93, -18, 42, -79, 119, 36, 47, 64, -93, 94, -58, 36, 3 [...]
+ b[122] = new byte[]{-56, -84, -45, -121, -104, 79, -89, -33, -49, 5, -26, 109, -83, -107, -20, 20, 112, 17, -9, 44, 14, 51, 120, 81, 104, 16, -28, -128, 111, 68, -45, -36, 5, 91, -61, 25, 15, 76, 76, 25, -24, 28, -89, 68, 43, 76, -105, 15, -15, 6, 14, 105, -120, 83, 13, 88, -90, 62, -85, 13, 77, 83, -90, -115, -40, -28, -67, 47, -74, 90, 24, -55, 91, -119, -107, 57, 116, 60, 40, -128, -3, -41, 38, -127, -76, -6, 62, 13, 43, 75, -28, 99, 32, 114, -41, 15, -28, -54, 21, 127, 85, 10 [...]
+ b[123] = new byte[]{114, -63, 102, -62, -16, -13, -96, -18, 8, 59, -84, -110, 12, 14, 1, -39, 94, -34, -104, 71, -83, 3, 0, -96, 59, -82, -77, -50, 87, -42, 111, 114, -125, -84, -9, -59, 101, -51, -55, -126, -66, 62, 118, 86, -108, -112, 66, 3, 29, -121, -117, 28, 68, -35, 78, -53, 22, 58, 93, -118, -84, -15, -63, 18, -59, 11, -92, 52, -47, -5, 115, -95, -70, -75, -37, -43, 10, -10, 54, -15, -30, 28, 91, -86, 79, 113, -98, 111, -95, 24, -61, 102, -91, 109, -12, -26, 95, 23, 33, - [...]
+ b[124] = new byte[]{-28, -119, -15, -68, -84, 41, -96, 37, 123, 16, -82, -4, 59, 53, 63, -76, -65, 127, 54, 98, -75, -32, -6, -16, -10, -45, -126, 3, 34, -66, -58, -107, 13, 45, -102, -30, -71, 81, 21, 118, 10, 104, 103, 78, 107, -106, 43, -97, 105, 64, -58, 28, 127, 29, 60, 7, -90, -16, 111, 67, 55, -11, 78, 62, 75, 65, -22, -11, -54, -75, -51, -92, 49, 72, 39, 49, 56, -103, -62, -1, -44, 85, -33, -79, -54, -87, -45, -16, -14, -60, 116, -44, 60, -84, 37, -79, -54, 32, -100, 45, [...]
+ b[125] = new byte[]{112, 76, 123, -95, 59, 18, 29, 101, 5, 62, 63, 118, 114, -53, 93, -53, -100, 6, 109, 23, 49, 31, -27, 81, 88, -33, 36, 104, -44, -45, 8, -11, -86, 73, -55, 50, 83, -43, -28, -2, 56, -7, -2, 8, -3, 12, 92, 35, 126, -64, -110, -89, -83, 49, -70, -41, -8, -2, -79, 90, -98, 59, 112, -86, -44, 96, -23, -46, 75, 63, -126, 64, -126, -109, -118, -77, 0, -27, 30, 46, -107, -73, -68, -59, -1, 14, -57, -119, -45, 31, -38, -57, 109, -106, -54, -77, 107, 38, 102, 79, 97, - [...]
+ b[126] = new byte[]{1, -27, -34, -75, 86, -29, -5, -71, -90, 26, 32, -84, -36, 17, -108, 73, -112, -53, -106, -83, -88, 116, -53, 13, -16, -112, 7, 64, -50, -72, 10, 92, -68, -53, -104, -16, -17, -109, -23, 33, 42, 28, 89, 17, 69, 66, 105, -105, 96, -2, -36, -112, -87, -83, -70, 18, 47, 15, -81, 71, -75, -100, 70, -124, -44, 108, -105, 89, 117, -127, 124, -54, 22, 27, 22, -54, 71, 17, -76, 111, 59, 23, -53, 18, -43, 75, -1, -117, -92, 47, 26, 36, 72, 13, 81, 6, 24, -116, -42, -81 [...]
+ b[127] = new byte[]{106, 61, 127, -13, -1, -108, -15, 83, -73, 15, 104, -128, -62, -12, 23, 103, -127, -12, 43, 11, 110, -52, 57, -72, 36, 32, -68, -5, 109, -100, 114, -87, 62, 83, 50, -81, -86, 49, -84, -13, -75, -25, -125, 7, -20, 49, -12, -92, 120, 101, 64, -117, -91, 65, -22, -41, -51, 37, 56, -40, 114, -42, -93, -19, 31, 29, -62, 29, -113, 33, -14, -46, -82, -10, -87, -121, 14, 48, 52, 29, -111, 18, 58, 101, -100, -6, 35, -96, -26, -3, 108, -43, 13, -75, 75, -35, 43, 118, -1 [...]
+ b[128] = new byte[]{-110, 35, 46, 23, -3, 66, 49, 25, 96, -95, 47, -18, 44, -87, -11, -104, -42, 69, 100, -47, -55, 54, 68, 80, -98, 43, -50, -81, 56, -4, 29, 0, 26, -125, 12, -17, 77, 123, -20, 26, 2, 61, -123, 117, -9, -87, -89, -103, 47, -33, -15, -4, -22, -66, 99, -111, 122, 14, 31, -80, 94, -113, -76, -110, -98, -119, 106, 1, 99, -67, -76, -55, 113, 4, -88, -64, 92, -56, -62, 14, -1, 87, -37, 26, -98, -51, 13, 19, 65, 35, -93, 14, 65, 125, -110, -81, -118, 17, 72, -29, -85, [...]
+ b[129] = new byte[]{97, 121, -126, 90, 24, -115, -49, -113, -56, -121, 44, 80, 33, -120, -32, 54, -8, -41, -7, 124, 3, -120, -12, -46, 4, -58, -123, 16, -71, -71, 95, -58, 56, -110, 113, -111, -98, 65, 120, -1, 56, -79, -14, 95, 112, 28, 22, -2, -20, 40, 31, -82, -66, 58, -84, 94, -34, -120, -116, -38, 0, 82, -29, 46, 56, -34, -61, 46, -73, 118, -32, 73, -119, 86, -60, 90, 58, -123, 59, 71, -18, -23, 63, 98, 34, 59, -124, 104, 93, -84, 78, -102, 111, -71, -109, 79, 31, 31, 52, -6 [...]
+ b[130] = new byte[]{24, -105, -44, -96, 24, -81, 91, -101, -86, 14, -107, 49, 77, 23, -29, 25, 99, 88, 124, -35, -1, 117, 49, 109, 117, 26, -126, 32, 126, 75, -39, -51, 103, 89, 125, 29, -127, -115, -37, 107, 95, -97, 91, -10, 23, -44, -24, 121, 107, 14, 37, 11, -96, 72, -118, 36, -31, -116, -102, 21, -43, 90, -51, -98, 85, -13, 109, -59, 28, 51, 47, -122, -80, 53, 20, 7, -60, 30, -14, 80, 111, 125, -17, -19, -31, 25, -115, 60, 29, 33, 86, 10, -46, -13, -39, -19, 110, -27, 52, 74 [...]
+ b[131] = new byte[]{121, 55, -85, 54, -50, -35, 58, -94, 64, -60, 12, 92, 49, 4, 103, 80, 55, 54, 112, 24, -10, -57, 72, -44, -42, 13, 67, -36, 111, -101, -37, 105, 3, -49, -78, 65, -52, -20, -65, -101, 24, 70, 92, 4, 55, -41, 125, 37, 106, -11, -116, -124, -119, -110, 6, 68, 94, 83, -20, -12, 3, 93, -60, 97, 83, 20, -65, -45, -59, -52, 62, -8, -20, -96, -81, -98, -49, -110, 10, -114, 118, 96, -47, -63, -45, -49, 122, 111, -119, 120, -18, -81, 33, -69, -56, -20, 15, 94, -45, 103, [...]
+ b[132] = new byte[]{-107, -70, -58, -78, 54, -13, 19, -99, -75, -85, -53, 115, 84, 117, 123, -67, -60, -49, 114, 21, 39, -52, -113, -44, 125, -28, 118, 71, -25, 38, 57, -83, -67, 98, 88, -49, 88, -72, 109, -11, 108, 118, 38, -72, -30, 42, -2, 14, 127, -103, -41, 123, -71, 47, -122, 47, -117, 97, 75, -123, 86, -88, 26, -88, -127, 97, 11, -13, -53, 110, -93, -123, -119, 61, -107, 101, -59, -24, -83, 58, 26, 69, 63, 66, 46, 42, -107, -27, -66, -89, 28, -33, -45, -57, 62, -110, 35, - [...]
+ b[133] = new byte[]{-103, 12, 0, 63, 54, 51, 127, 28, -3, 21, 113, 34, 103, -93, 60, -69, 90, 13, -36, 66, 91, 21, -119, -115, 85, -6, 102, -6, 61, 3, -86, 5, 62, 56, -14, 56, 81, 17, -63, 34, -79, 120, -58, -9, 76, -68, 3, -25, -47, 107, -102, -83, -76, 50, -3, -107, 77, -47, -30, -117, -19, 46, 10, -36, -53, -38, -97, 71, -27, 3, 6, -103, 116, -113, -98, -28, 122, 100, 127, 19, -88, 25, 58, 124, 14, 78, 68, 21, 53, -29, -103, -97, -20, -8, 106, 39, 120, -15, 16, 16, 99, 85, 60, [...]
+ b[134] = new byte[]{-36, 110, -99, -41, 101, 24, -30, 94, 86, -20, -39, -16, -48, 18, -12, 30, 117, 98, 86, 15, 82, 116, 75, -117, 50, -89, -103, -61, 45, 17, -108, -108, 127, 98, -41, 32, 119, -7, -120, -60, -117, -105, 92, 9, 70, -122, -8, 104, 95, -91, -36, -40, 17, -108, -19, 26, 83, -117, 88, -40, 43, 48, 60, -21, 43, -91, -46, 63, 122, 117, -73, 4, -32, -21, 107, 63, -39, 84, 4, -103, 92, 99, -41, -106, -49, -97, 93, -68, -70, -118, -57, 11, 119, 112, 67, -127, -62, -77, -3 [...]
+ b[135] = new byte[]{3, 24, 43, 100, -92, -59, -109, -110, 111, 44, 45, -61, 4, 0, -121, -62, -99, -70, -24, 92, 74, 35, -4, -89, -12, 95, -75, -75, -119, 51, 47, -98, -47, 86, -50, 71, 8, -106, 18, -29, -75, 110, 27, 68, -12, 19, 108, 42, -52, 122, -100, 44, -93, -48, 49, -107, -108, -18, -10, -47, -93, 35, 6, 52, -67, -39, -75, -95, -24, 102, -92, -22, 114, -81, 74, 90, -45, -125, 11, -29, -89, 18, -12, -110, -17, -19, 79, -31, 41, -112, 14, -20, -117, -40, -62, 127, 120, -112, [...]
+ b[136] = new byte[]{106, -39, 6, -14, 93, -108, -4, -39, -26, -5, 50, -18, -17, 56, -34, -98, -73, -36, 1, 84, 9, 49, 74, -121, -118, 97, 89, -35, -60, 31, 105, 74, 120, -85, 42, -59, -97, 85, 34, -63, -99, -9, -113, -82, -107, -73, -83, -34, 85, -92, -1, 21, 124, 126, 46, 81, 39, -80, 121, -6, 1, 51, -63, 50, -99, -30, 17, -118, 1, 37, -116, -115, -90, 60, -1, -51, 19, -95, 5, -73, 51, -99, 0, 12, 117, 101, 19, 115, 34, -120, -98, -7, -58, -33, 30, -124, -58, 0, 87, -89, 42, -97 [...]
+ b[137] = new byte[]{117, -56, -108, -42, 100, -121, 25, -64, 113, 56, 5, 65, -128, -100, 123, -28, -98, -125, 105, 7, 65, 101, -12, -56, -51, 13, 56, 90, 25, 36, 117, 19, 46, -92, -26, 86, 74, 123, -11, -9, 24, 115, -14, 24, -114, -7, -103, -37, 6, -48, -55, -72, -18, 107, 30, -59, 6, -52, 127, -29, 97, -89, 31, 103, 32, -112, -9, 110, 43, -95, 27, -28, -121, 116, -11, -53, 27, 11, -85, 118, -101, 100, -107, 2, 15, -47, -40, -100, -12, -60, 45, 88, 111, -41, -25, 4, 23, -122, -88 [...]
+ b[138] = new byte[]{118, 4, 117, 60, -10, -100, 6, -5, 72, 44, 25, -96, -33, 123, 61, 41, 107, 110, 115, -82, -25, 118, 29, -21, 8, 118, 127, -108, -125, 123, -80, 67, 96, 108, 90, -119, 67, 46, 67, 11, 117, -56, 120, 116, -43, -18, -123, -99, -6, -46, 80, 105, 124, 104, 11, -67, 127, 73, 78, -47, -49, -93, -126, -108, 3, 10, 92, -74, -52, -49, -59, 58, 68, -8, -86, -97, 115, 59, 49, 16, -112, 112, 55, -51, -116, 14, 92, 8, -39, 39, 93, 63, 68, -121, 63, -56, 100, 95, -5, -107, - [...]
+ b[139] = new byte[]{-43, 15, 43, 126, -99, 71, -72, 107, 49, -70, -76, -32, 24, -58, -92, -58, 62, 82, -64, -47, 123, 18, 44, 87, -59, 83, -25, 124, 96, 3, 88, 55, 50, -126, 30, 66, -44, 19, 23, -86, 34, -11, 2, -27, 87, 57, 81, 78, -79, -84, -99, 124, -75, -122, 11, -62, -101, -121, -14, 98, 47, -95, -2, -41, 105, 88, -84, -47, -108, 79, -36, -119, 68, -116, -47, 14, 46, 23, -54, 83, 39, -83, -116, 1, -73, 0, -119, -114, -127, -46, -117, -121, -79, -49, -110, -74, -118, 30, 120, [...]
+ b[140] = new byte[]{-61, 77, 83, -100, -13, -1, 23, 117, 103, -117, 119, -63, 117, 93, -10, 6, 118, -37, -32, -99, 69, 113, -74, -124, -7, 121, -8, -30, 122, 57, -70, 14, -5, 83, -63, 82, -42, 4, -90, -36, -70, -119, -13, 36, -14, 93, -37, -77, -105, -101, -10, 119, 0, 68, 127, 56, -124, 125, 59, -78, -86, 7, -117, 46, -64, -104, 76, 24, -41, -103, -125, -120, 29, 10, 44, 18, 94, -125, -56, 9, 39, -69, -123, -54, -25, 103, -112, 91, -31, 94, -77, -41, -110, -77, 99, 106, -8, 110, [...]
+ b[141] = new byte[]{57, -4, -56, 23, 127, 19, -89, -104, 53, 91, -105, -107, 110, -71, 43, 49, -19, 12, -101, -73, -76, -64, 22, 32, -26, 21, 111, 46, -103, -1, -28, -59, -71, 56, 87, 38, 68, 59, -127, -89, 94, 90, -55, 16, 103, 39, 91, 1, 35, -35, -2, 8, -39, 116, 47, 3, -4, 67, 76, -3, 33, 113, 99, 76, 68, 121, -128, 118, 117, 41, -15, -68, 53, 95, -88, 105, -62, -115, 27, -74, -104, -83, -75, 31, -74, 68, -117, -2, -125, -33, 68, -45, -34, -49, -91, 52, 22, -27, -96, -67, 90, [...]
+ b[142] = new byte[]{-30, 26, 23, -46, -56, -22, -106, 68, -119, 61, 74, -70, -37, -72, -119, -112, -42, 17, 110, -48, -2, 87, 106, -124, -84, 43, -109, -118, 70, -98, 68, 49, 25, -67, 81, -42, -65, 55, 111, -62, 62, 22, -41, 28, 73, -113, 63, -78, 28, 3, 122, -49, 97, 35, 9, 104, -99, 113, 43, 21, -127, 55, -93, 67, 86, -57, -14, -28, -13, 38, 8, 127, -50, -83, -14, 25, 68, -84, 38, -126, 86, -83, -25, 42, -58, -56, 30, -15, -79, 1, -114, 73, -66, -87, 67, -68, 27, 121, 0, -100, [...]
+ b[143] = new byte[]{51, -9, 114, -41, -116, 77, 109, -109, 17, 124, 120, -118, 40, 87, 102, 15, -13, -85, 16, 31, -68, 49, -20, 107, 68, -17, 38, 50, 29, 34, -28, -70, -51, 3, -107, -108, -76, -75, -35, -63, 71, -64, -54, -58, 38, 106, 95, 120, 49, 42, 13, 37, -8, 38, -64, 96, -88, -88, -36, 37, 89, -112, 86, -42, 74, 80, 104, -9, 106, -78, -71, -10, 114, -9, 58, 37, -58, 86, -12, 89, 78, -57, 78, -61, 17, 18, 70, 109, -98, -91, -22, -121, -37, -51, -107, -96, 23, -20, -97, -6, 2 [...]
+ b[144] = new byte[]{26, 2, -21, -38, 23, 119, -100, -82, -72, 33, -101, -12, 38, 75, 10, 1, 63, -14, 36, -44, 55, -15, -84, -82, 91, 32, 103, 88, -72, -41, 108, 73, -109, -45, -113, 20, 14, -102, 108, -82, -71, -49, -22, 24, -92, 70, -114, 111, -39, 57, 71, 26, 16, -10, 117, -52, 6, -12, -46, -54, -36, -8, 124, 34, -126, 40, -11, 103, -10, -67, -107, -127, 7, -28, -116, 35, -47, 105, -127, -100, 65, 88, -79, 35, -64, 118, -50, 90, -63, -38, 17, 3, 21, -79, 7, -28, -33, -63, 22, 6 [...]
+ b[145] = new byte[]{91, -39, 74, 112, -80, -22, 52, 100, 0, 27, -5, 10, 64, -42, -111, -103, -29, -108, -104, -78, 123, 25, -61, 13, -88, 22, -122, 103, -82, 125, 70, 120, -21, -23, 20, -21, 126, 121, -92, -89, -106, 125, -103, -32, 11, -97, 5, -24, 30, 51, -29, -51, 36, 3, 38, 117, 88, -79, -113, -79, -56, -55, -18, 62, 9, 122, -128, -59, 64, -124, 9, -66, 94, -102, -40, 86, -101, 39, 123, -117, -19, -5, -70, 35, 82, -90, -81, 84, -16, 106, 47, 46, 93, -74, 120, 105, -42, -89, - [...]
+ b[146] = new byte[]{-119, -126, -25, -26, 31, 101, 34, 16, -1, -57, -39, -88, 104, -12, 103, 77, 126, -90, 36, 66, 74, 78, 24, 56, 89, 124, 82, -20, -118, -47, -37, 54, -27, 31, 110, -82, 58, 66, 13, -49, 71, 73, 53, 50, 85, 122, -37, 52, 100, -42, 3, -98, -55, -45, -20, -99, -94, 35, 118, 58, -123, 53, 86, 60, 106, 24, 83, -113, 73, -36, 29, -117, -124, 36, 68, -77, 64, -39, 67, 112, -69, -45, -51, 5, -74, 35, -100, 124, 118, -33, 4, -77, 103, -48, 60, -126, 43, 82, -34, 0, 46, [...]
+ b[147] = new byte[]{74, 84, 73, 17, -50, -25, -91, 53, 47, 66, -81, 18, -128, 22, 10, -103, 86, 63, -33, 1, -40, -89, 104, 44, 15, 22, -97, 55, -14, 75, 82, -31, 42, 18, 57, -106, 50, -43, -69, 127, 16, 18, -117, -25, -113, 95, -120, 38, 36, -102, -117, -124, 62, 109, -8, 6, 113, -120, 44, 24, 43, 114, -9, 113, -21, -119, -57, -124, -30, -87, 88, 9, -49, -57, 122, -79, -50, -33, -127, 101, -27, -70, 29, 74, -8, 23, 6, 61, -74, 123, -8, 42, -72, 86, -56, 26, -20, -111, 1, 85, -23, [...]
+ b[148] = new byte[]{0, 9, 91, 25, 30, -98, -112, -77, -77, -57, -120, 105, -87, -108, -44, -87, 85, 16, -48, 82, -10, 8, 90, 96, 8, -61, -87, -24, 43, -82, 83, 57, 18, -99, 101, -23, 82, 59, -50, -119, 32, -28, 52, -8, 40, 76, -8, 41, -126, 104, 55, -71, -117, -52, -79, 126, 55, -102, 67, -58, 80, 96, -67, 107, 0, -45, -123, 124, -122, 66, 30, -82, -35, 103, -42, -74, 104, 98, 61, 26, -105, -98, 49, 94, -109, -31, 15, 119, 66, -40, 94, -101, 59, -42, 122, 39, -24, 47, 102, -18, 1 [...]
+ b[149] = new byte[]{-99, 101, -101, 6, 28, -50, 110, -84, 4, 22, 31, -45, -120, -92, 68, 114, -54, -117, 97, -76, 99, 33, -58, 95, -108, -102, 104, -105, 94, -116, -117, -122, 3, 47, -95, 25, -82, 45, -74, -87, 25, -45, -126, -80, 109, 33, -113, -121, -119, -28, -40, 90, -30, -38, 9, 41, 63, 7, -43, -100, 98, -24, -24, 75, -94, 91, -27, -36, -96, -36, 84, 58, 92, 95, 91, 97, -93, 80, 27, 29, -80, -16, 49, -32, -57, 73, 54, -98, -95, -1, -47, 77, 108, 1, 77, 36, 126, -35, -10, 104 [...]
+ b[150] = new byte[]{88, -39, 53, 70, 125, -86, -76, 111, -96, -109, 64, 4, 123, 10, -32, -93, -26, -111, 108, -38, -58, -32, 40, 16, -92, -28, 124, 82, -114, -36, -38, 109, -105, 65, -113, 12, 84, 59, -72, -71, 16, 58, -81, 54, 6, 25, -40, 42, 77, -62, 2, 42, 76, -67, 50, -15, -34, 37, -29, 86, 84, 5, -50, -58, 96, 56, 17, -43, -48, -37, 18, 45, 20, -105, 80, -73, 16, 109, -25, -89, 26, 119, -47, 65, 93, 123, 51, -37, 92, -107, -80, -6, -7, 119, -114, 119, 105, -72, -69, 79, 117, [...]
+ b[151] = new byte[]{-63, 89, -94, 59, -87, -99, 127, 102, -102, -122, -78, 101, 114, 105, -63, 15, 68, 26, -25, -52, -68, 2, -4, -41, -76, -98, 120, 34, 108, 96, 60, -77, -25, -48, -48, -112, 34, -71, -108, -57, 51, 89, 53, 51, -125, 19, 117, -114, -22, 70, 76, 16, 38, -109, -3, 17, 42, 79, 115, -24, 56, 26, 125, -78, -48, -121, 8, 83, 87, 56, -50, -3, -17, -46, 120, -32, 45, 89, 69, 77, 50, 60, 40, 90, -45, 73, 16, 100, 17, 121, 18, 103, 11, -118, -43, 66, -49, 93, 45, 63, -56, [...]
+ b[152] = new byte[]{58, -120, -107, 102, -117, 8, -8, -95, -76, 17, -108, -18, -7, 106, 71, -18, 66, -120, 75, 25, -114, -41, 52, 88, 105, 35, -52, 4, -59, -76, 3, 36, 98, 11, 104, -103, 84, 73, 14, 50, 34, -89, -41, 101, -49, -88, -128, -46, 91, -7, 21, 3, -97, 28, -66, -1, -14, -79, 48, 51, 40, -76, -18, -17, -59, 40, -6, -59, 92, 37, -19, -64, -76, -73, 96, 120, 15, 111, 57, 17, 68, 45, 51, -8, -65, -48, -48, -2, 96, 38, 122, 23, -73, 55, -52, 100, -7, 84, -53, 99, -84, 71, 90 [...]
+ b[153] = new byte[]{-9, -74, 85, -79, 54, 48, 15, -59, 107, -128, -35, 69, 56, -124, 89, -14, 57, -68, 56, -56, 43, -60, 109, -24, -43, -94, 104, 98, -45, -43, 89, 122, 125, 114, 56, -27, -127, 122, -109, 49, -107, 108, -95, 106, -9, -90, -66, -23, -71, -36, 62, 45, -118, 53, 18, 60, -9, 38, -104, -108, 60, 122, -106, 113, -99, -113, 90, -75, -84, -20, -12, 117, 106, 70, 6, -69, 7, 66, 4, 118, 47, 8, 100, -36, 101, -127, 94, -1, 43, -75, 0, 31, 48, -25, 54, 44, -105, 87, -119, 71 [...]
+ b[154] = new byte[]{-48, -44, -104, 41, 59, -63, 40, -94, 39, -64, -65, 79, 39, -6, 86, 81, 101, 87, -30, 8, -59, -34, 40, 44, 3, 106, -86, 64, -53, 17, 123, 13, 37, 35, 82, -36, 8, 29, 124, 120, 96, -104, -109, 64, 39, -55, 64, -98, -9, -36, 57, -107, 97, -58, 21, 67, 12, 120, 126, -125, 101, -56, -128, -54, 85, -122, 120, 57, -11, -12, -105, 115, 84, -28, -34, -68, 21, -92, -36, -78, 46, -116, -115, 70, -66, -63, 1, -34, -123, 106, 127, 102, 101, -12, -122, 94, 12, 96, -109, -2 [...]
+ b[155] = new byte[]{-26, -119, 62, -83, -126, 56, 44, 40, 6, 107, 106, 108, 25, 67, 127, 125, -39, 19, -38, 4, 4, 78, -128, 125, 29, 24, -123, 93, 10, 94, -39, -121, 16, -68, 67, 118, -49, -74, 37, 36, 33, 19, -57, -120, -46, 91, 13, 58, -89, -106, 60, -75, -105, 41, -45, -55, -88, 40, -42, 48, 80, -98, 52, 14, -13, -23, 26, 80, -58, -5, 5, 41, 22, 16, -72, -110, 71, -24, -22, -8, -6, 78, -80, -93, -25, 42, 22, 38, 46, 67, -6, -89, 96, 31, 100, -12, 37, -27, -116, -13, 71, 24, 55 [...]
+ b[156] = new byte[]{40, 124, -45, 106, 85, 61, -64, -12, -89, 34, 56, 121, -125, 71, -121, -117, 81, -44, 104, 91, -97, -60, -102, 87, -90, 48, -34, -48, -35, -16, 16, -94, 13, -87, -72, 51, -123, -72, -9, 41, -2, 42, 90, 54, -10, 119, 80, 62, -48, -55, 110, -10, -42, 5, -2, 64, 61, 56, -40, -35, 107, -104, -40, 125, 24, 2, 30, 110, 102, 82, -72, -44, -47, 48, 50, 79, -79, 16, 21, -99, -82, -23, 97, 74, -2, -63, 71, 63, -17, -78, 112, -108, 36, -14, 78, -54, 44, -11, 22, 3, -109, [...]
+ b[157] = new byte[]{70, -78, 85, -60, -126, -88, 13, 123, 66, -66, 37, -116, -65, -12, -105, 48, -18, 54, 14, 126, -108, 88, -30, -125, -53, 104, 97, -40, 4, -105, -78, -60, -12, 123, -31, -70, -101, -79, 117, -37, 125, 34, 37, 105, 68, 55, 76, 1, 71, -54, 126, 6, 84, -35, 6, 20, 43, -97, 110, 116, -9, -61, -9, 43, 94, -85, 6, 102, 105, -49, 15, -7, 118, 103, -84, 32, -100, 97, 96, -10, -116, -32, 104, -102, 58, 12, -19, 22, 59, -110, 113, 56, 36, -103, 93, 9, -105, -5, -39, -11, [...]
+ b[158] = new byte[]{-77, 46, 45, -26, -79, 64, -17, -111, -111, 4, 79, -125, -87, -81, 108, 67, 24, -49, -106, -30, -83, -4, -103, -60, 99, -98, 32, -72, 121, -54, -87, -57, 38, -57, 113, -58, -117, 34, 116, -115, 64, 62, 122, -34, 23, 59, -59, -32, -21, -36, 2, 3, -36, 85, -60, -106, 80, 47, -67, -13, -13, 73, -107, 124, -121, -8, -36, 114, 10, 59, 24, 49, 79, 98, 35, 27, -79, 10, 48, -32, -1, -85, 30, -115, -100, -60, -17, 123, -128, 107, -54, 8, 11, -75, -78, -48, 81, -28, 95, [...]
+ b[159] = new byte[]{102, -49, -63, 124, 90, 22, 34, 102, 26, -69, 103, 89, 45, -66, -55, -99, -25, -109, 66, -98, -20, 67, 78, -78, -94, 113, 42, -47, -122, -72, 4, -45, -119, 27, 47, -7, 116, 97, -8, -38, -116, -19, -48, -6, 79, -40, -122, 127, 75, -97, 23, -19, -21, 21, -127, -50, -93, 3, 92, -73, 5, -52, 99, -36, -61, -24, 14, 52, 9, 73, -111, -59, 18, -44, 119, 27, 125, 83, -15, -31, 121, 58, -109, -43, 11, -121, 112, -10, -49, 92, -106, 89, 76, -45, -101, 111, 113, -23, -84, [...]
+ b[160] = new byte[]{-123, -41, -125, 38, -28, 103, -103, -65, 42, -12, 70, 30, 115, -49, -97, -70, -44, -1, 10, -6, -95, -90, -86, 20, 118, -39, -122, -24, 77, -11, 70, -74, 9, 14, -49, 122, 51, -107, -97, -98, 15, 116, 32, 74, -85, -99, -58, 94, -30, -75, 88, 14, -121, 17, 100, -83, -73, 118, -6, -83, 37, -93, -31, 77, 64, 87, 94, 30, 54, 35, 35, 37, 82, 122, -24, -21, -46, -120, -5, 78, -7, 22, -10, 24, -62, 5, 90, 81, -35, 116, -81, -79, 49, 88, -50, 89, -20, 48, -112, -37, 31 [...]
+ b[161] = new byte[]{10, 80, -126, 58, -3, 38, 15, -33, -1, 45, 29, 14, -118, -63, -33, 106, 108, 92, 78, -7, -91, -64, -62, -32, 0, -124, 45, -34, 22, -50, -115, 19, -28, 95, 1, 32, 104, 60, -49, -46, -18, -117, 55, -64, 77, -63, -45, -107, -61, -30, -31, -83, -68, -52, 35, -52, -48, -52, 123, -24, -18, 97, -113, -111, 2, 2, 121, -24, -90, -1, 31, -79, -104, 99, -48, -74, 101, -89, 95, 16, -106, -120, -67, 110, 127, -1, 30, 71, -107, -82, -53, -47, 43, -14, -55, 19, 7, -54, -58, [...]
+ b[162] = new byte[]{22, -49, -128, -104, 80, -89, 82, -65, -30, -101, 15, 3, -48, 106, 77, -119, -46, 15, -10, -84, 22, -13, 36, 64, -50, 107, 106, 61, 47, -81, 79, -87, -7, 83, -122, 5, 65, -54, 96, 111, 57, -21, 96, -18, 19, 62, -87, 21, 23, 106, 51, -42, 106, 96, 45, -126, 32, -57, -5, -74, 94, -54, -19, -106, 49, -105, -29, -94, -33, 99, -61, -78, 80, -10, -80, -29, -9, 90, -33, -60, 6, -98, 10, 8, -107, 45, -100, 55, 77, 92, -128, -35, -34, 125, 40, -52, -106, 118, 69, -93, [...]
+ b[163] = new byte[]{-62, 3, -72, 13, -47, -103, -53, -40, 53, -36, -117, -114, -122, 66, 70, 37, -60, -24, -56, -69, -126, 5, 89, -67, 79, -9, 60, -87, -114, 13, 58, 23, -107, 83, 83, 86, -38, 15, 44, 60, -118, 62, 70, 33, 44, 73, 36, -4, -77, 30, -66, 38, 31, -64, -2, 70, -126, -59, -117, -55, -12, 43, 32, -100, 24, -39, 48, -59, -111, -79, -35, -4, -36, 118, 64, -96, -101, 100, -57, 2, -81, -54, -121, -105, -49, 48, -2, -90, -31, 111, -88, -92, 1, 16, -86, -27, 4, 76, 31, 125, [...]
+ b[164] = new byte[]{18, 69, -19, -45, 100, -102, 69, 66, 35, 22, 106, 11, -57, 35, -70, 55, -24, 34, 47, -120, -128, -31, -10, 52, 19, 22, -88, -6, 104, -32, 17, -10, 126, 90, -2, -80, -9, -111, -105, 28, 18, 53, -58, 86, 12, 84, -71, 14, 114, 123, -67, -99, -21, 28, -67, -59, -48, 31, 67, -85, -88, -65, 110, 126, -118, -60, 81, 49, -109, 74, 13, -100, -117, -82, -26, -32, 106, -16, 2, -68, -116, -53, -18, 94, 82, -114, -5, 67, -111, -87, 88, -89, -20, -125, -55, -61, 108, 63, 26 [...]
+ b[165] = new byte[]{58, -32, 106, -57, -110, -59, 38, -70, 17, 108, 57, -8, -41, -18, 26, -52, 81, -27, 42, 12, 58, 108, -56, 27, -79, 17, -102, 43, -43, 39, 62, -8, -71, -59, -7, -107, -31, 34, -48, -39, -116, -56, -122, -118, 70, -117, 81, 121, -20, -66, -81, 42, -23, 26, 91, 69, -27, 22, 79, -59, 127, -108, -35, -28, -125, 2, -19, 79, -92, -67, 114, -91, 127, -57, -58, 32, -124, 60, 21, -95, -56, -46, -10, -56, 95, -49, 78, 38, 80, 106, -108, -128, -86, 126, -44, -115, -119, 8 [...]
+ b[166] = new byte[]{72, -17, -17, 14, -54, -103, 13, -46, 38, 57, -47, -11, -10, -58, 72, -20, 85, 21, -122, 92, 117, 16, -115, 23, 70, -65, 0, -83, 59, -128, 27, -111, 124, 44, 50, -69, -24, 23, 45, -40, 46, -33, 93, 53, 40, -62, 41, 87, -100, -107, -95, 67, 27, -37, 26, 43, -91, -111, 65, -110, -71, 88, -43, 63, 93, -77, 105, -49, 91, 74, 20, 105, -81, 82, -9, -71, -57, 94, -18, 125, 95, -9, 47, -51, 112, 114, 66, -63, -38, -109, 46, -82, -47, 99, 40, 8, -75, 14, 41, -91, 1, -9 [...]
+ b[167] = new byte[]{-75, -110, -1, -88, 0, -116, 59, -44, -77, -102, 2, 97, 89, 3, 44, 108, -88, 4, -26, 83, -64, 17, -68, 103, -36, -44, 123, -25, 78, 34, -106, 0, 43, 71, -56, -5, -70, -3, 74, 23, -114, -82, 67, 40, -21, -112, 73, -14, 6, -118, -26, 96, 31, -6, -100, -79, -91, 30, 27, 122, -40, -124, 31, -76, -58, 31, -26, 1, -23, 28, 87, -45, -66, -23, 17, 40, 95, 59, -37, -52, -120, 96, 0, 24, 28, -12, 63, 90, 49, -13, 29, -43, 82, -87, 66, 106, 23, 102, -68, 68, 78, -110, -6 [...]
+ b[168] = new byte[]{25, 23, -69, -72, 93, 112, 31, -97, -5, -44, 29, -17, -104, 97, 126, -92, -35, -57, -12, -14, -114, -42, -46, -16, -78, 118, -12, 15, -113, -49, -101, -77, -18, -28, -96, 30, -32, -25, -34, -106, 71, -59, 32, 24, 50, -114, -22, 25, -82, -105, -124, -112, 102, 103, 111, -22, -97, -8, -87, -5, 42, -35, 97, 15, 6, 43, -4, -58, -3, 123, 11, -80, 57, 123, 27, 34, -110, -48, 50, 7, -31, -48, -114, 87, -80, -6, -42, -95, -57, 110, 87, 57, -2, -69, -9, 38, -35, -54, - [...]
+ b[169] = new byte[]{-16, 16, -59, -69, -19, -67, -106, -101, 101, 25, 40, -36, 101, -18, -32, -123, 102, -108, -128, -116, -37, -71, 74, 76, -27, 112, -59, 110, -46, 85, 64, -15, 29, -35, -80, 4, -47, -63, -111, -107, 1, 61, 18, 18, -105, -117, -110, 127, 34, -55, 24, 54, -76, 55, -25, -69, 65, -124, 15, -108, 52, 51, 87, 10, 38, -45, -40, 6, 70, -89, 53, -128, 115, 1, 58, 116, -1, -75, -32, 91, -111, 47, -111, -79, -86, 31, -19, 122, -29, -40, 42, -66, 72, 34, 126, -52, -35, 38, [...]
+ b[170] = new byte[]{-78, 35, -46, 92, 62, 46, -33, -91, -104, -75, 59, -17, 15, 52, 101, 20, -8, -82, 100, -55, -47, 115, 58, -53, -35, -32, 53, -25, -34, 121, 36, 48, -100, -21, -11, 118, 10, -5, -70, -101, -15, -49, 59, -94, 113, -94, 12, 78, -47, -90, 19, 103, -101, 94, -115, -128, -50, 33, -104, 1, -53, -115, 3, -127, 70, 76, -88, -14, 118, 34, -106, 35, -78, 101, 27, -114, 50, 84, -14, -17, -50, -89, 8, 76, -94, 126, 118, -26, 109, -17, -48, 70, 37, -65, 40, -10, 66, -99, -2 [...]
+ b[171] = new byte[]{-5, -3, 120, 62, 113, 80, 85, -98, -63, 76, 114, -108, -66, 68, -19, 70, -74, 18, -19, 105, -49, 52, 62, 96, 103, -106, -14, 50, 21, 43, 12, -71, 9, 107, -91, 15, 5, 94, -13, -46, 122, -61, 50, 39, -60, -93, -9, 80, 125, 74, -73, 18, 48, -94, 27, -84, 70, 86, 26, -44, -68, 12, -32, -58, -93, -112, 101, 53, -75, 99, -38, 125, 51, 66, -106, 91, -31, 52, 94, -16, -112, -90, -111, -59, -90, -29, 42, 23, 91, -40, -80, 93, 14, 15, -96, 12, -120, 79, 73, -76, 105, -4 [...]
+ b[172] = new byte[]{-33, 82, 53, -115, -81, -127, -7, -86, 41, 42, 76, -19, 27, 50, 88, -68, -111, 22, 2, -56, 114, -96, 0, 21, -25, 43, -34, -32, -71, -49, -46, 71, 72, -103, 68, 26, 84, 68, -46, -70, -114, 66, 12, -122, 43, -17, 51, 60, 48, 32, -11, 121, -125, -23, 46, 39, 38, 26, 112, 62, 11, -35, -69, -93, -44, 6, 1, 82, -9, 114, -45, -65, 12, 37, -95, 54, 41, -42, -20, -39, -98, 96, -125, 62, -93, -121, 98, 40, 25, 3, 62, 49, -26, 73, 102, -66, -98, -82, 39, -81, -24, 14, 10 [...]
+ b[173] = new byte[]{93, -76, 95, 14, -95, -98, -35, -25, -120, -42, -47, -15, -15, 73, -49, -99, -32, -63, -25, -77, 124, 85, -28, -110, -51, 124, -43, 8, -44, -96, -60, -31, 31, 119, -89, 127, -70, 126, 66, 15, 17, -58, -6, 110, 48, -34, -46, 27, -75, 41, 50, -31, 29, -66, -52, -63, 126, 75, -105, 17, -67, 51, -80, 103, -5, -34, 122, 6, 45, 44, -92, -15, 3, 73, -107, 121, -43, -117, 22, 71, -31, -2, -2, 13, -128, -14, 126, 52, 69, 62, 115, 41, 91, 73, 38, 75, 1, -32, 104, 124, 5 [...]
+ b[174] = new byte[]{-116, 97, 35, -4, 6, -127, 121, -10, -100, -10, -29, -100, -104, 107, -114, -10, 113, -2, 55, -20, -52, -80, 46, 42, 1, -18, -103, 80, 67, 12, 33, 119, 83, 26, 116, -106, -105, -75, -19, -45, -7, -54, -85, 35, -93, -35, -111, -10, -29, -47, -16, -112, -97, 27, -97, -112, -66, -47, -68, -50, -91, 13, 94, 3, 115, -15, 18, -82, -111, 124, -93, 43, -116, 114, 79, 38, 100, -39, 94, -76, -124, 73, 56, -33, -113, 122, 13, 45, 79, -62, -86, -96, -50, -87, -33, 51, -99 [...]
+ b[175] = new byte[]{68, 12, -51, 11, 25, 79, -39, 47, -4, 45, -10, -58, -74, 84, -125, 74, 26, 49, -15, -60, -96, -104, -109, 14, 115, 108, 79, 22, -49, 30, -127, -107, 73, -117, 9, 102, -99, 45, -38, 5, 98, -113, 69, -74, -15, -111, -104, -107, 85, -119, 110, -32, 99, 73, 55, 6, -24, 113, -50, -99, -126, -71, 118, -16, 117, -64, -79, -120, -92, 19, -100, 48, -95, 13, 76, 120, -30, 86, 83, 124, -13, 22, 38, 4, 54, 30, -46, 44, 20, 31, -115, 83, -48, 30, -25, 28, -74, -65, 15, -23 [...]
+ b[176] = new byte[]{-45, -56, 102, 102, -101, 65, 24, -94, -86, 71, -92, 51, -12, 99, 92, -39, 105, 53, 122, -40, 20, -4, -86, 32, 110, 35, -48, -104, 8, 121, 33, 121, 83, 5, -49, 123, 14, -31, 19, -96, -66, 1, 111, -49, 61, -99, -13, -101, 85, 15, -42, 122, 89, -94, 9, 47, 48, 18, 52, -127, 118, 105, -27, -110, 69, 59, -3, -66, 84, 79, 115, -8, -109, 90, 65, -23, -100, 79, 31, -44, 37, 118, 62, 90, 107, 57, 0, -1, 32, -101, -46, 76, -61, 124, -103, 92, 116, 83, -95, -43, -32, 28 [...]
+ b[177] = new byte[]{-48, 104, 107, -127, -76, -110, 28, -14, -42, -73, 36, -74, -102, 116, -79, -84, -48, 35, -3, -36, -85, 21, 7, 49, 34, 3, -29, 79, -65, -69, -15, 38, 117, 101, 49, -100, -45, 123, -20, -102, 86, 120, 103, -10, -50, 59, -50, 4, -9, 34, -101, -107, -94, 57, 117, 33, -43, 94, -68, 121, -20, -67, 36, -118, 66, -4, -74, 2, -126, -80, 9, 20, 52, -19, -27, -1, -116, -17, -28, 87, -62, -83, 20, -32, 27, 30, 44, 21, 49, 65, -44, -45, 92, 45, -52, 26, -126, 75, -59, -51 [...]
+ b[178] = new byte[]{-39, 81, -94, 49, 95, -33, -38, 19, 89, 2, 60, 55, 125, -41, -121, -57, -4, 17, 33, 92, -34, 63, 77, 124, -107, -100, -89, -49, 4, -78, 72, 111, -13, 64, 28, 114, 70, 104, -73, 98, 98, -107, 102, 104, 119, 104, -101, -89, -70, 42, -90, -67, -37, 116, -112, -98, -91, 95, -77, 60, 5, -88, -40, 28, -16, -127, -110, -94, 78, -57, -54, 15, 39, -14, -75, -96, 0, -15, 86, 9, -38, -67, -98, -67, 116, -90, 43, 75, 47, 127, 62, 110, -84, 31, 24, -59, -83, -44, -77, -11, [...]
+ b[179] = new byte[]{-120, -60, -126, -121, 89, -71, -67, -53, 119, 11, -78, -60, -97, -100, 10, 69, -117, 90, -105, 59, -58, -22, -110, -102, -124, 109, 125, -83, 54, -6, 103, -38, -69, -7, -69, -125, -80, -62, -7, -56, -50, -115, -88, 59, -24, 87, 27, 119, 14, -2, -54, 71, 7, 82, -33, 17, -65, 63, 38, -5, 108, -111, -81, 67, 102, -72, 22, 20, 103, 77, -82, 7, -68, -5, -27, -35, -54, 73, 116, -56, 2, 10, -5, 23, 121, 117, -24, 48, -66, 41, 31, 49, 101, -92, -3, 27, 54, -61, 40, - [...]
+ b[180] = new byte[]{-124, -34, 62, -57, -5, 10, -12, 84, 89, -97, -103, 101, 107, 14, -1, 92, 49, -80, -122, -35, -63, 112, -116, 64, 20, -2, 9, -96, 106, -107, 64, 44, 60, 115, -110, 14, -107, 42, -118, 16, -27, 98, 98, -53, 53, -102, 123, -28, -93, -87, 21, -83, -51, -94, 48, 64, 60, -121, -60, 108, -80, -98, 29, 36, 26, 69, 13, -97, -37, -111, -24, 66, -54, 20, 38, 90, -101, 41, 102, -48, 47, 68, -34, 125, -102, 62, -89, -57, 68, -127, -126, 86, 6, 113, -61, -14, -82, 125, -34 [...]
}
/* These are chunked versions of the strings above (chunked by commons-codec-1.3.jar) */
@@ -250,140 +250,131 @@ public class Base64Codec13Test {
}
- /* Here are the randomly generated byte[] arrays we generated to exercise commons-codec-1.3.jar */
- private static void initBYTES() {
- final byte[][] b = BYTES;
- b[0] = new byte[]{};
- b[1] = new byte[]{-72};
- b[2] = new byte[]{-49, -36};
- b[3] = new byte[]{77, 15, -103};
- b[4] = new byte[]{110, 24, -44, 96};
- b[5] = new byte[]{-43, -61, -67, -75, -33};
- b[6] = new byte[]{-80, -52, 71, -96, -105, -7};
- b[7] = new byte[]{-115, 7, 15, -108, 59, 25, -49};
- b[8] = new byte[]{76, 6, -113, -99, -11, -65, 9, -123};
- b[9] = new byte[]{113, 116, -39, -69, 12, -41, 60, -29, 82};
- b[10] = new byte[]{46, -39, -1, 101, 53, 120, 34, 52, -6, 56};
- b[11] = new byte[]{-23, -8, 126, -115, -43, 55, -43, 35, -90, 90, -73};
- b[12] = new byte[]{19, -2, 76, -96, 62, 42, 10, -16, -18, 77, -63, 64};
- b[13] = new byte[]{-38, 127, 88, -55, -16, -116, -56, -59, -34, -103, -69, 108, -79};
- b[14] = new byte[]{-88, 25, 26, -36, 26, -70, 87, 125, 71, -103, -55, -121, -114, 70};
- b[15] = new byte[]{90, -4, -103, 123, -87, 16, -14, -100, -69, -101, 110, 110, 113, -84, 9};
- b[16] = new byte[]{-95, -118, 113, 51, 46, -127, 74, -106, 87, -123, 90, 78, 71, -89, 87, -104};
- b[63] = new byte[]{-55, -20, 69, 104, -46, -102, 63, -27, 100, 87, 1, 20, -65, 20, 23, 108, 45, 7, 72, 40, -65, -78, -77, -104, -19, -51, 55, -22, 84, -10, -27, -6, -20, -29, 24, -56, -66, -99, -75, -32, -111, -62, -125, -77, -117, -3, 118, 86, -36, -125, 30, -24, 32, -32, 72, -64, -102, 104, -113, 117, 121, 24, 12};
- b[64] = new byte[]{-66, 74, -96, -98, -30, 119, -90, 92, 77, -74, -117, -34, -120, -62, 110, 96, -77, 122, -63, -108, 11, -91, -67, -59, -125, -113, 63, -52, 121, 29, 22, -32, -18, 114, -29, 10, 89, 84, 78, -2, 120, -123, 70, 2, -84, 22, -89, 49, -85, -91, 96, 11, 28, 16, 109, -29, -30, 63, -37, 17, -97, 28, -5, -62};
- b[65] = new byte[]{96, 121, 44, -36, 96, -101, -38, -27, 69, -29, -74, 54, -76, 40, -98, -120, 49, -119, -13, -65, 81, -101, -105, 65, -123, 8, 80, -117, 54, 33, 125, 99, -88, -8, 26, -63, -37, -14, -66, 19, -68, 25, 89, 56, -99, -41, -119, 76, -92, -50, -76, -5, -112, -76, 55, -46, 77, 40, 7, 1, 17, 39, -86, 101, -110};
- b[66] = new byte[]{-49, -50, 121, -42, 57, -112, -89, -12, 44, -9, -101, 112, -37, 110, -66, 28, 33, -42, -82, -30, -79, -4, -101, -33, 4, 39, -48, -26, -99, 31, 23, -66, -26, -111, 42, 105, -21, -95, 57, -25, 104, -92, -38, 12, -100, -84, 16, 108, 48, 47, -51, 111, 57, -64, -127, 54, 104, 51, 54, 113, 122, 23, -55, -62, -18, 61};
- b[67] = new byte[]{86, -60, 118, -62, 26, -86, -2, -92, 38, -33, -115, -66, 76, -36, -11, -106, 3, -103, 50, -123, -101, -92, 44, -2, -110, 61, -77, 126, 90, -76, -97, 30, -46, -3, 23, -124, 84, -11, 9, 114, -88, 12, -75, 92, -21, -81, 97, 85, 64, -9, -63, 0, 126, 85, 70, 52, 126, -122, 76, 112, -65, -122, -20, -79, 9, -84, -15};
- b[68] = new byte[]{-25, 25, -120, -89, -57, 84, 37, -100, -28, -118, -62, 36, -72, 67, -20, -100, -11, -17, -52, 55, -116, -93, -113, 42, 88, 87, -57, 34, 125, -102, -65, 120, -21, -26, -86, 25, 28, 43, 52, 45, -13, 68, -55, -22, 66, -34, -3, -84, 107, 73, -62, 83, 65, 101, -86, -55, -125, -55, 50, 57, -1, 104, -19, -25, 59, 11, -75, 93};
- b[69] = new byte[]{-76, 97, 32, 94, 56, 37, 80, 31, 77, 108, 43, 98, 75, -49, 0, 122, -46, -19, 70, -88, 66, 2, 120, 115, 57, 66, -107, -126, -10, -55, 100, 122, -114, 3, -84, 124, -72, -22, 43, 3, 91, 119, 53, -58, -120, 3, 77, 25, -87, -77, -40, 0, -69, -72, 47, 50, 38, -30, 46, 37, 0, -65, 80, -126, 33, -1, 38, 14, -37};
- b[70] = new byte[]{-128, 91, 113, 18, 22, 9, 106, 16, -26, 83, -105, 105, -71, -42, 44, -23, -108, -20, -88, 12, 126, -77, 104, -2, -45, -96, 52, -51, -20, -101, -35, 78, -25, -123, -111, 108, 110, 64, -125, -107, -37, 52, 17, -123, 40, -87, -22, -39, -87, -109, -26, -20, 94, -126, 12, -29, -125, -35, -43, 59, -99, -119, -98, -108, 77, 3, -57, 35, 14, -12};
- b[71] = new byte[]{-113, -8, 127, -44, -100, -96, 96, 14, 91, -114, -37, 113, -51, 12, 107, -26, 0, 109, -126, 31, -128, 97, 90, 51, -124, 94, 22, -126, -9, 20, -2, 14, 61, -65, 72, 84, -53, -95, 93, -123, -10, 94, -64, 98, -66, 62, 27, 115, -113, -76, 90, 108, -114, 105, -37, 53, -14, -50, -7, 38, 45, 7, 69, -123, -46, 57, 82, 110, 14, -26, -52};
- b[72] = new byte[]{-101, -23, 24, 84, 106, 35, 33, 30, 105, -127, -68, -5, -92, 98, 102, -38, 15, -73, -86, -87, 59, 126, 25, 119, 114, -116, 26, -39, -27, 107, -122, 72, -69, 90, -121, -14, -53, 9, -47, 123, 58, -109, -60, -23, 1, -127, 81, 115, -22, 114, -84, -14, -84, 105, 109, -74, -13, 0, -73, 45, 112, -9, -116, -78, -97, 93, -91, 117, 31, -71, 66, 107};
- b[73] = new byte[]{-92, -10, -122, -100, -54, -12, 81, -119, -91, 118, 114, 85, -109, -15, 126, -35, 96, -119, 39, 90, -10, -94, -37, -61, -28, -94, 93, -73, 107, -75, 70, 116, -70, 47, 8, 71, -121, 2, -62, -87, -11, -68, 59, -12, 4, -125, -115, -42, 119, 18, -88, -104, 98, -1, 36, -51, -9, -74, 127, -63, -10, -109, 15, -96, -123, 52, 65, 49, -93, -85, 97, -111, -93};
- b[74] = new byte[]{-104, -20, 115, 27, 44, -90, -23, 63, -63, -60, 37, 121, -99, 40, -120, 96, -55, 95, 1, 73, -126, 55, -72, 45, -17, -26, 83, 50, 13, 100, 119, -61, -19, -118, -71, 62, 36, 94, 93, -109, -59, 18, 109, 96, 110, -1, -42, 111, 54, 14, 89, -70, 34, 66, 120, 108, 31, 105, 90, 106, -91, -99, -54, -9, 36, -123, -20, 47, 59, 38, -5, -75, 69, 65};
- b[75] = new byte[]{85, -126, -50, 32, 78, 3, -98, 28, 73, -97, 113, 74, 75, -3, -111, 28, 113, -40, 46, 86, 98, 25, 87, 85, -2, 78, 46, 5, -69, 64, 96, 117, 18, 78, -108, 115, 105, -90, 15, 24, -48, 21, -115, -45, 112, 109, 49, -56, -118, 25, -98, -70, 79, -7, 97, 5, 50, -16, -47, 108, -60, -118, 38, -8, -72, -69, 110, 117, -94, 6, -127, -54, 4, -13, -5};
- b[76] = new byte[]{-19, -6, 12, -92, -99, 19, -110, 112, -102, -74, 53, 34, 75, 27, 103, -72, -92, -94, -49, -124, 47, -105, -8, -99, 89, -113, 84, 42, 36, -27, -114, -124, 7, 103, -32, -68, 109, -59, 44, 114, 114, 63, 109, -102, -11, -35, -18, -128, -65, 37, 33, -29, -77, 37, -91, -47, -81, -52, -119, -76, -26, -91, 29, 49, 101, -117, -95, -110, 78, 104, 102, 47, 14, 107, -21, 89};
- b[77] = new byte[]{-113, 20, 18, 26, 33, 108, -7, -67, 83, 124, 78, 37, 13, 64, 15, 80, -14, 116, 73, 103, -108, -126, 93, 55, -84, -82, -102, -70, 39, -106, 37, -58, -85, 12, -127, -52, -9, -72, 6, 56, 115, 38, -56, 123, -99, 68, -54, -92, 102, 98, 36, -59, -124, 96, 98, 0, -126, 82, 15, -55, 121, 79, 117, 57, -112, -9, -76, -66, 20, -5, 3, 97, 74, 28, -80, 123, -49};
- b[78] = new byte[]{80, 105, -121, -2, 9, 123, -73, 112, -28, -13, 77, 111, 70, 20, 67, 17, -72, 44, 125, 40, 109, 29, -99, 96, 101, 9, -8, 40, -42, 121, 66, -52, 55, 90, 33, -93, 91, 66, 38, 34, 117, 71, 107, -30, -46, 28, 28, -53, 82, 60, 2, -47, -99, -25, 92, -18, 34, -29, -32, -94, 41, -118, -128, -78, -109, -107, -120, 78, -106, -87, 85, 24, -15, -108, -107, -48, -24, 56};
- b[79] = new byte[]{-63, -47, 40, 98, 98, 110, 70, 120, 54, -49, 98, 36, 2, 36, -96, 39, 80, -106, -39, 81, 59, 31, -70, 23, -91, -123, -124, 20, 83, -68, -100, 109, 27, 102, 126, -49, 30, 20, -4, 43, 40, 90, 59, 106, -30, 118, 95, 30, 80, 76, -84, -115, -83, 21, 92, 80, -14, 66, -92, -96, 102, 123, -35, 80, -86, -62, 25, -22, 86, 25, -106, -16, -45, -3, 27, 15, 11, 55, 2};
- b[80] = new byte[]{-26, 70, 106, -126, -75, 27, -73, -22, -51, -28, 21, -128, 117, -41, -108, -74, 111, 83, 25, 62, 55, -67, -118, 65, -24, -9, -78, 67, 4, -14, -53, -43, 91, -81, 79, -108, -1, -124, 51, -53, 66, 48, -33, -76, 90, -37, -35, -57, -102, 73, -87, -127, 12, -18, 73, -59, 105, 112, -120, -123, 25, 115, -64, 21, 108, 19, -95, 31, -101, -94, -4, 46, -19, -91, -29, -117, -15, 103, 51, 9};
- b[81] = new byte[]{19, -114, -69, 48, -55, -119, 110, 108, 47, -16, -23, -100, -39, 55, 92, -56, -54, -1, -33, 64, 124, -117, 53, -101, 127, -32, -128, -72, -101, 112, -21, -74, -11, -125, -37, 107, -124, 46, -89, -32, 102, 39, 94, 55, -106, -12, 54, 47, -103, 106, 8, 36, -4, 116, -50, -11, 63, 67, -24, 42, -65, 71, 45, 122, 13, -101, -57, -45, -10, -102, -72, 12, 12, 4, 91, -23, -24, 40, -62, -88, -15};
- b[82] = new byte[]{86, -101, 124, -123, -122, -8, -113, 29, 69, -5, -76, 68, 95, -78, -70, -26, -2, -98, 59, -111, 117, 24, 56, 63, 43, -60, -107, 45, 96, -46, -89, 75, 43, -70, -106, 4, 66, 64, 85, 71, 25, -63, -11, -39, -95, 74, -113, 87, 30, -100, -8, 11, -54, 81, -105, -54, -4, -39, -4, 87, 102, -23, -90, 17, -2, 20, -40, -24, 116, 14, 42, 121, -82, 115, 109, 12, -65, -120, 38, -14, -4, -107};
- b[121] = new byte[]{-123, -2, -67, -58, -65, 102, -76, 87, -8, 55, 120, -10, -72, 15, 76, -128, -78, -7, 103, 47, 120, 30, 59, -2, 85, 8, -67, -29, -30, -46, -13, -34, -10, 36, -104, 3, 28, 36, 14, -64, -2, 112, -123, -44, 36, 87, -28, -119, -91, 121, 34, -56, 113, -102, 74, -60, 56, 126, 23, -87, 63, 12, -18, 101, -63, 41, 96, 68, 126, 109, -23, -14, -42, 63, -116, -48, 116, -103, 123, 126, -116, 117, 18, 33, -107, 58, -89, -93, -18, 42, -79, 119, 36, 47, 64, -93, 94, -58, 36, 3 [...]
- b[122] = new byte[]{-56, -84, -45, -121, -104, 79, -89, -33, -49, 5, -26, 109, -83, -107, -20, 20, 112, 17, -9, 44, 14, 51, 120, 81, 104, 16, -28, -128, 111, 68, -45, -36, 5, 91, -61, 25, 15, 76, 76, 25, -24, 28, -89, 68, 43, 76, -105, 15, -15, 6, 14, 105, -120, 83, 13, 88, -90, 62, -85, 13, 77, 83, -90, -115, -40, -28, -67, 47, -74, 90, 24, -55, 91, -119, -107, 57, 116, 60, 40, -128, -3, -41, 38, -127, -76, -6, 62, 13, 43, 75, -28, 99, 32, 114, -41, 15, -28, -54, 21, 127, 85, 10 [...]
- b[123] = new byte[]{114, -63, 102, -62, -16, -13, -96, -18, 8, 59, -84, -110, 12, 14, 1, -39, 94, -34, -104, 71, -83, 3, 0, -96, 59, -82, -77, -50, 87, -42, 111, 114, -125, -84, -9, -59, 101, -51, -55, -126, -66, 62, 118, 86, -108, -112, 66, 3, 29, -121, -117, 28, 68, -35, 78, -53, 22, 58, 93, -118, -84, -15, -63, 18, -59, 11, -92, 52, -47, -5, 115, -95, -70, -75, -37, -43, 10, -10, 54, -15, -30, 28, 91, -86, 79, 113, -98, 111, -95, 24, -61, 102, -91, 109, -12, -26, 95, 23, 33, - [...]
- b[124] = new byte[]{-28, -119, -15, -68, -84, 41, -96, 37, 123, 16, -82, -4, 59, 53, 63, -76, -65, 127, 54, 98, -75, -32, -6, -16, -10, -45, -126, 3, 34, -66, -58, -107, 13, 45, -102, -30, -71, 81, 21, 118, 10, 104, 103, 78, 107, -106, 43, -97, 105, 64, -58, 28, 127, 29, 60, 7, -90, -16, 111, 67, 55, -11, 78, 62, 75, 65, -22, -11, -54, -75, -51, -92, 49, 72, 39, 49, 56, -103, -62, -1, -44, 85, -33, -79, -54, -87, -45, -16, -14, -60, 116, -44, 60, -84, 37, -79, -54, 32, -100, 45, [...]
- b[125] = new byte[]{112, 76, 123, -95, 59, 18, 29, 101, 5, 62, 63, 118, 114, -53, 93, -53, -100, 6, 109, 23, 49, 31, -27, 81, 88, -33, 36, 104, -44, -45, 8, -11, -86, 73, -55, 50, 83, -43, -28, -2, 56, -7, -2, 8, -3, 12, 92, 35, 126, -64, -110, -89, -83, 49, -70, -41, -8, -2, -79, 90, -98, 59, 112, -86, -44, 96, -23, -46, 75, 63, -126, 64, -126, -109, -118, -77, 0, -27, 30, 46, -107, -73, -68, -59, -1, 14, -57, -119, -45, 31, -38, -57, 109, -106, -54, -77, 107, 38, 102, 79, 97, - [...]
- b[126] = new byte[]{1, -27, -34, -75, 86, -29, -5, -71, -90, 26, 32, -84, -36, 17, -108, 73, -112, -53, -106, -83, -88, 116, -53, 13, -16, -112, 7, 64, -50, -72, 10, 92, -68, -53, -104, -16, -17, -109, -23, 33, 42, 28, 89, 17, 69, 66, 105, -105, 96, -2, -36, -112, -87, -83, -70, 18, 47, 15, -81, 71, -75, -100, 70, -124, -44, 108, -105, 89, 117, -127, 124, -54, 22, 27, 22, -54, 71, 17, -76, 111, 59, 23, -53, 18, -43, 75, -1, -117, -92, 47, 26, 36, 72, 13, 81, 6, 24, -116, -42, -81 [...]
- b[127] = new byte[]{106, 61, 127, -13, -1, -108, -15, 83, -73, 15, 104, -128, -62, -12, 23, 103, -127, -12, 43, 11, 110, -52, 57, -72, 36, 32, -68, -5, 109, -100, 114, -87, 62, 83, 50, -81, -86, 49, -84, -13, -75, -25, -125, 7, -20, 49, -12, -92, 120, 101, 64, -117, -91, 65, -22, -41, -51, 37, 56, -40, 114, -42, -93, -19, 31, 29, -62, 29, -113, 33, -14, -46, -82, -10, -87, -121, 14, 48, 52, 29, -111, 18, 58, 101, -100, -6, 35, -96, -26, -3, 108, -43, 13, -75, 75, -35, 43, 118, -1 [...]
- b[128] = new byte[]{-110, 35, 46, 23, -3, 66, 49, 25, 96, -95, 47, -18, 44, -87, -11, -104, -42, 69, 100, -47, -55, 54, 68, 80, -98, 43, -50, -81, 56, -4, 29, 0, 26, -125, 12, -17, 77, 123, -20, 26, 2, 61, -123, 117, -9, -87, -89, -103, 47, -33, -15, -4, -22, -66, 99, -111, 122, 14, 31, -80, 94, -113, -76, -110, -98, -119, 106, 1, 99, -67, -76, -55, 113, 4, -88, -64, 92, -56, -62, 14, -1, 87, -37, 26, -98, -51, 13, 19, 65, 35, -93, 14, 65, 125, -110, -81, -118, 17, 72, -29, -85, [...]
- b[129] = new byte[]{97, 121, -126, 90, 24, -115, -49, -113, -56, -121, 44, 80, 33, -120, -32, 54, -8, -41, -7, 124, 3, -120, -12, -46, 4, -58, -123, 16, -71, -71, 95, -58, 56, -110, 113, -111, -98, 65, 120, -1, 56, -79, -14, 95, 112, 28, 22, -2, -20, 40, 31, -82, -66, 58, -84, 94, -34, -120, -116, -38, 0, 82, -29, 46, 56, -34, -61, 46, -73, 118, -32, 73, -119, 86, -60, 90, 58, -123, 59, 71, -18, -23, 63, 98, 34, 59, -124, 104, 93, -84, 78, -102, 111, -71, -109, 79, 31, 31, 52, -6 [...]
- b[130] = new byte[]{24, -105, -44, -96, 24, -81, 91, -101, -86, 14, -107, 49, 77, 23, -29, 25, 99, 88, 124, -35, -1, 117, 49, 109, 117, 26, -126, 32, 126, 75, -39, -51, 103, 89, 125, 29, -127, -115, -37, 107, 95, -97, 91, -10, 23, -44, -24, 121, 107, 14, 37, 11, -96, 72, -118, 36, -31, -116, -102, 21, -43, 90, -51, -98, 85, -13, 109, -59, 28, 51, 47, -122, -80, 53, 20, 7, -60, 30, -14, 80, 111, 125, -17, -19, -31, 25, -115, 60, 29, 33, 86, 10, -46, -13, -39, -19, 110, -27, 52, 74 [...]
- b[131] = new byte[]{121, 55, -85, 54, -50, -35, 58, -94, 64, -60, 12, 92, 49, 4, 103, 80, 55, 54, 112, 24, -10, -57, 72, -44, -42, 13, 67, -36, 111, -101, -37, 105, 3, -49, -78, 65, -52, -20, -65, -101, 24, 70, 92, 4, 55, -41, 125, 37, 106, -11, -116, -124, -119, -110, 6, 68, 94, 83, -20, -12, 3, 93, -60, 97, 83, 20, -65, -45, -59, -52, 62, -8, -20, -96, -81, -98, -49, -110, 10, -114, 118, 96, -47, -63, -45, -49, 122, 111, -119, 120, -18, -81, 33, -69, -56, -20, 15, 94, -45, 103, [...]
- b[132] = new byte[]{-107, -70, -58, -78, 54, -13, 19, -99, -75, -85, -53, 115, 84, 117, 123, -67, -60, -49, 114, 21, 39, -52, -113, -44, 125, -28, 118, 71, -25, 38, 57, -83, -67, 98, 88, -49, 88, -72, 109, -11, 108, 118, 38, -72, -30, 42, -2, 14, 127, -103, -41, 123, -71, 47, -122, 47, -117, 97, 75, -123, 86, -88, 26, -88, -127, 97, 11, -13, -53, 110, -93, -123, -119, 61, -107, 101, -59, -24, -83, 58, 26, 69, 63, 66, 46, 42, -107, -27, -66, -89, 28, -33, -45, -57, 62, -110, 35, - [...]
- b[133] = new byte[]{-103, 12, 0, 63, 54, 51, 127, 28, -3, 21, 113, 34, 103, -93, 60, -69, 90, 13, -36, 66, 91, 21, -119, -115, 85, -6, 102, -6, 61, 3, -86, 5, 62, 56, -14, 56, 81, 17, -63, 34, -79, 120, -58, -9, 76, -68, 3, -25, -47, 107, -102, -83, -76, 50, -3, -107, 77, -47, -30, -117, -19, 46, 10, -36, -53, -38, -97, 71, -27, 3, 6, -103, 116, -113, -98, -28, 122, 100, 127, 19, -88, 25, 58, 124, 14, 78, 68, 21, 53, -29, -103, -97, -20, -8, 106, 39, 120, -15, 16, 16, 99, 85, 60, [...]
- b[134] = new byte[]{-36, 110, -99, -41, 101, 24, -30, 94, 86, -20, -39, -16, -48, 18, -12, 30, 117, 98, 86, 15, 82, 116, 75, -117, 50, -89, -103, -61, 45, 17, -108, -108, 127, 98, -41, 32, 119, -7, -120, -60, -117, -105, 92, 9, 70, -122, -8, 104, 95, -91, -36, -40, 17, -108, -19, 26, 83, -117, 88, -40, 43, 48, 60, -21, 43, -91, -46, 63, 122, 117, -73, 4, -32, -21, 107, 63, -39, 84, 4, -103, 92, 99, -41, -106, -49, -97, 93, -68, -70, -118, -57, 11, 119, 112, 67, -127, -62, -77, -3 [...]
- b[135] = new byte[]{3, 24, 43, 100, -92, -59, -109, -110, 111, 44, 45, -61, 4, 0, -121, -62, -99, -70, -24, 92, 74, 35, -4, -89, -12, 95, -75, -75, -119, 51, 47, -98, -47, 86, -50, 71, 8, -106, 18, -29, -75, 110, 27, 68, -12, 19, 108, 42, -52, 122, -100, 44, -93, -48, 49, -107, -108, -18, -10, -47, -93, 35, 6, 52, -67, -39, -75, -95, -24, 102, -92, -22, 114, -81, 74, 90, -45, -125, 11, -29, -89, 18, -12, -110, -17, -19, 79, -31, 41, -112, 14, -20, -117, -40, -62, 127, 120, -112, [...]
- b[136] = new byte[]{106, -39, 6, -14, 93, -108, -4, -39, -26, -5, 50, -18, -17, 56, -34, -98, -73, -36, 1, 84, 9, 49, 74, -121, -118, 97, 89, -35, -60, 31, 105, 74, 120, -85, 42, -59, -97, 85, 34, -63, -99, -9, -113, -82, -107, -73, -83, -34, 85, -92, -1, 21, 124, 126, 46, 81, 39, -80, 121, -6, 1, 51, -63, 50, -99, -30, 17, -118, 1, 37, -116, -115, -90, 60, -1, -51, 19, -95, 5, -73, 51, -99, 0, 12, 117, 101, 19, 115, 34, -120, -98, -7, -58, -33, 30, -124, -58, 0, 87, -89, 42, -97 [...]
- b[137] = new byte[]{117, -56, -108, -42, 100, -121, 25, -64, 113, 56, 5, 65, -128, -100, 123, -28, -98, -125, 105, 7, 65, 101, -12, -56, -51, 13, 56, 90, 25, 36, 117, 19, 46, -92, -26, 86, 74, 123, -11, -9, 24, 115, -14, 24, -114, -7, -103, -37, 6, -48, -55, -72, -18, 107, 30, -59, 6, -52, 127, -29, 97, -89, 31, 103, 32, -112, -9, 110, 43, -95, 27, -28, -121, 116, -11, -53, 27, 11, -85, 118, -101, 100, -107, 2, 15, -47, -40, -100, -12, -60, 45, 88, 111, -41, -25, 4, 23, -122, -88 [...]
- b[138] = new byte[]{118, 4, 117, 60, -10, -100, 6, -5, 72, 44, 25, -96, -33, 123, 61, 41, 107, 110, 115, -82, -25, 118, 29, -21, 8, 118, 127, -108, -125, 123, -80, 67, 96, 108, 90, -119, 67, 46, 67, 11, 117, -56, 120, 116, -43, -18, -123, -99, -6, -46, 80, 105, 124, 104, 11, -67, 127, 73, 78, -47, -49, -93, -126, -108, 3, 10, 92, -74, -52, -49, -59, 58, 68, -8, -86, -97, 115, 59, 49, 16, -112, 112, 55, -51, -116, 14, 92, 8, -39, 39, 93, 63, 68, -121, 63, -56, 100, 95, -5, -107, - [...]
- b[139] = new byte[]{-43, 15, 43, 126, -99, 71, -72, 107, 49, -70, -76, -32, 24, -58, -92, -58, 62, 82, -64, -47, 123, 18, 44, 87, -59, 83, -25, 124, 96, 3, 88, 55, 50, -126, 30, 66, -44, 19, 23, -86, 34, -11, 2, -27, 87, 57, 81, 78, -79, -84, -99, 124, -75, -122, 11, -62, -101, -121, -14, 98, 47, -95, -2, -41, 105, 88, -84, -47, -108, 79, -36, -119, 68, -116, -47, 14, 46, 23, -54, 83, 39, -83, -116, 1, -73, 0, -119, -114, -127, -46, -117, -121, -79, -49, -110, -74, -118, 30, 120, [...]
- b[140] = new byte[]{-61, 77, 83, -100, -13, -1, 23, 117, 103, -117, 119, -63, 117, 93, -10, 6, 118, -37, -32, -99, 69, 113, -74, -124, -7, 121, -8, -30, 122, 57, -70, 14, -5, 83, -63, 82, -42, 4, -90, -36, -70, -119, -13, 36, -14, 93, -37, -77, -105, -101, -10, 119, 0, 68, 127, 56, -124, 125, 59, -78, -86, 7, -117, 46, -64, -104, 76, 24, -41, -103, -125, -120, 29, 10, 44, 18, 94, -125, -56, 9, 39, -69, -123, -54, -25, 103, -112, 91, -31, 94, -77, -41, -110, -77, 99, 106, -8, 110, [...]
- b[141] = new byte[]{57, -4, -56, 23, 127, 19, -89, -104, 53, 91, -105, -107, 110, -71, 43, 49, -19, 12, -101, -73, -76, -64, 22, 32, -26, 21, 111, 46, -103, -1, -28, -59, -71, 56, 87, 38, 68, 59, -127, -89, 94, 90, -55, 16, 103, 39, 91, 1, 35, -35, -2, 8, -39, 116, 47, 3, -4, 67, 76, -3, 33, 113, 99, 76, 68, 121, -128, 118, 117, 41, -15, -68, 53, 95, -88, 105, -62, -115, 27, -74, -104, -83, -75, 31, -74, 68, -117, -2, -125, -33, 68, -45, -34, -49, -91, 52, 22, -27, -96, -67, 90, [...]
- b[142] = new byte[]{-30, 26, 23, -46, -56, -22, -106, 68, -119, 61, 74, -70, -37, -72, -119, -112, -42, 17, 110, -48, -2, 87, 106, -124, -84, 43, -109, -118, 70, -98, 68, 49, 25, -67, 81, -42, -65, 55, 111, -62, 62, 22, -41, 28, 73, -113, 63, -78, 28, 3, 122, -49, 97, 35, 9, 104, -99, 113, 43, 21, -127, 55, -93, 67, 86, -57, -14, -28, -13, 38, 8, 127, -50, -83, -14, 25, 68, -84, 38, -126, 86, -83, -25, 42, -58, -56, 30, -15, -79, 1, -114, 73, -66, -87, 67, -68, 27, 121, 0, -100, [...]
- b[143] = new byte[]{51, -9, 114, -41, -116, 77, 109, -109, 17, 124, 120, -118, 40, 87, 102, 15, -13, -85, 16, 31, -68, 49, -20, 107, 68, -17, 38, 50, 29, 34, -28, -70, -51, 3, -107, -108, -76, -75, -35, -63, 71, -64, -54, -58, 38, 106, 95, 120, 49, 42, 13, 37, -8, 38, -64, 96, -88, -88, -36, 37, 89, -112, 86, -42, 74, 80, 104, -9, 106, -78, -71, -10, 114, -9, 58, 37, -58, 86, -12, 89, 78, -57, 78, -61, 17, 18, 70, 109, -98, -91, -22, -121, -37, -51, -107, -96, 23, -20, -97, -6, 2 [...]
- b[144] = new byte[]{26, 2, -21, -38, 23, 119, -100, -82, -72, 33, -101, -12, 38, 75, 10, 1, 63, -14, 36, -44, 55, -15, -84, -82, 91, 32, 103, 88, -72, -41, 108, 73, -109, -45, -113, 20, 14, -102, 108, -82, -71, -49, -22, 24, -92, 70, -114, 111, -39, 57, 71, 26, 16, -10, 117, -52, 6, -12, -46, -54, -36, -8, 124, 34, -126, 40, -11, 103, -10, -67, -107, -127, 7, -28, -116, 35, -47, 105, -127, -100, 65, 88, -79, 35, -64, 118, -50, 90, -63, -38, 17, 3, 21, -79, 7, -28, -33, -63, 22, 6 [...]
- b[145] = new byte[]{91, -39, 74, 112, -80, -22, 52, 100, 0, 27, -5, 10, 64, -42, -111, -103, -29, -108, -104, -78, 123, 25, -61, 13, -88, 22, -122, 103, -82, 125, 70, 120, -21, -23, 20, -21, 126, 121, -92, -89, -106, 125, -103, -32, 11, -97, 5, -24, 30, 51, -29, -51, 36, 3, 38, 117, 88, -79, -113, -79, -56, -55, -18, 62, 9, 122, -128, -59, 64, -124, 9, -66, 94, -102, -40, 86, -101, 39, 123, -117, -19, -5, -70, 35, 82, -90, -81, 84, -16, 106, 47, 46, 93, -74, 120, 105, -42, -89, - [...]
- b[146] = new byte[]{-119, -126, -25, -26, 31, 101, 34, 16, -1, -57, -39, -88, 104, -12, 103, 77, 126, -90, 36, 66, 74, 78, 24, 56, 89, 124, 82, -20, -118, -47, -37, 54, -27, 31, 110, -82, 58, 66, 13, -49, 71, 73, 53, 50, 85, 122, -37, 52, 100, -42, 3, -98, -55, -45, -20, -99, -94, 35, 118, 58, -123, 53, 86, 60, 106, 24, 83, -113, 73, -36, 29, -117, -124, 36, 68, -77, 64, -39, 67, 112, -69, -45, -51, 5, -74, 35, -100, 124, 118, -33, 4, -77, 103, -48, 60, -126, 43, 82, -34, 0, 46, [...]
- b[147] = new byte[]{74, 84, 73, 17, -50, -25, -91, 53, 47, 66, -81, 18, -128, 22, 10, -103, 86, 63, -33, 1, -40, -89, 104, 44, 15, 22, -97, 55, -14, 75, 82, -31, 42, 18, 57, -106, 50, -43, -69, 127, 16, 18, -117, -25, -113, 95, -120, 38, 36, -102, -117, -124, 62, 109, -8, 6, 113, -120, 44, 24, 43, 114, -9, 113, -21, -119, -57, -124, -30, -87, 88, 9, -49, -57, 122, -79, -50, -33, -127, 101, -27, -70, 29, 74, -8, 23, 6, 61, -74, 123, -8, 42, -72, 86, -56, 26, -20, -111, 1, 85, -23, [...]
- b[148] = new byte[]{0, 9, 91, 25, 30, -98, -112, -77, -77, -57, -120, 105, -87, -108, -44, -87, 85, 16, -48, 82, -10, 8, 90, 96, 8, -61, -87, -24, 43, -82, 83, 57, 18, -99, 101, -23, 82, 59, -50, -119, 32, -28, 52, -8, 40, 76, -8, 41, -126, 104, 55, -71, -117, -52, -79, 126, 55, -102, 67, -58, 80, 96, -67, 107, 0, -45, -123, 124, -122, 66, 30, -82, -35, 103, -42, -74, 104, 98, 61, 26, -105, -98, 49, 94, -109, -31, 15, 119, 66, -40, 94, -101, 59, -42, 122, 39, -24, 47, 102, -18, 1 [...]
- b[149] = new byte[]{-99, 101, -101, 6, 28, -50, 110, -84, 4, 22, 31, -45, -120, -92, 68, 114, -54, -117, 97, -76, 99, 33, -58, 95, -108, -102, 104, -105, 94, -116, -117, -122, 3, 47, -95, 25, -82, 45, -74, -87, 25, -45, -126, -80, 109, 33, -113, -121, -119, -28, -40, 90, -30, -38, 9, 41, 63, 7, -43, -100, 98, -24, -24, 75, -94, 91, -27, -36, -96, -36, 84, 58, 92, 95, 91, 97, -93, 80, 27, 29, -80, -16, 49, -32, -57, 73, 54, -98, -95, -1, -47, 77, 108, 1, 77, 36, 126, -35, -10, 104 [...]
- b[150] = new byte[]{88, -39, 53, 70, 125, -86, -76, 111, -96, -109, 64, 4, 123, 10, -32, -93, -26, -111, 108, -38, -58, -32, 40, 16, -92, -28, 124, 82, -114, -36, -38, 109, -105, 65, -113, 12, 84, 59, -72, -71, 16, 58, -81, 54, 6, 25, -40, 42, 77, -62, 2, 42, 76, -67, 50, -15, -34, 37, -29, 86, 84, 5, -50, -58, 96, 56, 17, -43, -48, -37, 18, 45, 20, -105, 80, -73, 16, 109, -25, -89, 26, 119, -47, 65, 93, 123, 51, -37, 92, -107, -80, -6, -7, 119, -114, 119, 105, -72, -69, 79, 117, [...]
- b[151] = new byte[]{-63, 89, -94, 59, -87, -99, 127, 102, -102, -122, -78, 101, 114, 105, -63, 15, 68, 26, -25, -52, -68, 2, -4, -41, -76, -98, 120, 34, 108, 96, 60, -77, -25, -48, -48, -112, 34, -71, -108, -57, 51, 89, 53, 51, -125, 19, 117, -114, -22, 70, 76, 16, 38, -109, -3, 17, 42, 79, 115, -24, 56, 26, 125, -78, -48, -121, 8, 83, 87, 56, -50, -3, -17, -46, 120, -32, 45, 89, 69, 77, 50, 60, 40, 90, -45, 73, 16, 100, 17, 121, 18, 103, 11, -118, -43, 66, -49, 93, 45, 63, -56, [...]
- b[152] = new byte[]{58, -120, -107, 102, -117, 8, -8, -95, -76, 17, -108, -18, -7, 106, 71, -18, 66, -120, 75, 25, -114, -41, 52, 88, 105, 35, -52, 4, -59, -76, 3, 36, 98, 11, 104, -103, 84, 73, 14, 50, 34, -89, -41, 101, -49, -88, -128, -46, 91, -7, 21, 3, -97, 28, -66, -1, -14, -79, 48, 51, 40, -76, -18, -17, -59, 40, -6, -59, 92, 37, -19, -64, -76, -73, 96, 120, 15, 111, 57, 17, 68, 45, 51, -8, -65, -48, -48, -2, 96, 38, 122, 23, -73, 55, -52, 100, -7, 84, -53, 99, -84, 71, 90 [...]
- b[153] = new byte[]{-9, -74, 85, -79, 54, 48, 15, -59, 107, -128, -35, 69, 56, -124, 89, -14, 57, -68, 56, -56, 43, -60, 109, -24, -43, -94, 104, 98, -45, -43, 89, 122, 125, 114, 56, -27, -127, 122, -109, 49, -107, 108, -95, 106, -9, -90, -66, -23, -71, -36, 62, 45, -118, 53, 18, 60, -9, 38, -104, -108, 60, 122, -106, 113, -99, -113, 90, -75, -84, -20, -12, 117, 106, 70, 6, -69, 7, 66, 4, 118, 47, 8, 100, -36, 101, -127, 94, -1, 43, -75, 0, 31, 48, -25, 54, 44, -105, 87, -119, 71 [...]
- b[154] = new byte[]{-48, -44, -104, 41, 59, -63, 40, -94, 39, -64, -65, 79, 39, -6, 86, 81, 101, 87, -30, 8, -59, -34, 40, 44, 3, 106, -86, 64, -53, 17, 123, 13, 37, 35, 82, -36, 8, 29, 124, 120, 96, -104, -109, 64, 39, -55, 64, -98, -9, -36, 57, -107, 97, -58, 21, 67, 12, 120, 126, -125, 101, -56, -128, -54, 85, -122, 120, 57, -11, -12, -105, 115, 84, -28, -34, -68, 21, -92, -36, -78, 46, -116, -115, 70, -66, -63, 1, -34, -123, 106, 127, 102, 101, -12, -122, 94, 12, 96, -109, -2 [...]
- b[155] = new byte[]{-26, -119, 62, -83, -126, 56, 44, 40, 6, 107, 106, 108, 25, 67, 127, 125, -39, 19, -38, 4, 4, 78, -128, 125, 29, 24, -123, 93, 10, 94, -39, -121, 16, -68, 67, 118, -49, -74, 37, 36, 33, 19, -57, -120, -46, 91, 13, 58, -89, -106, 60, -75, -105, 41, -45, -55, -88, 40, -42, 48, 80, -98, 52, 14, -13, -23, 26, 80, -58, -5, 5, 41, 22, 16, -72, -110, 71, -24, -22, -8, -6, 78, -80, -93, -25, 42, 22, 38, 46, 67, -6, -89, 96, 31, 100, -12, 37, -27, -116, -13, 71, 24, 55 [...]
- b[156] = new byte[]{40, 124, -45, 106, 85, 61, -64, -12, -89, 34, 56, 121, -125, 71, -121, -117, 81, -44, 104, 91, -97, -60, -102, 87, -90, 48, -34, -48, -35, -16, 16, -94, 13, -87, -72, 51, -123, -72, -9, 41, -2, 42, 90, 54, -10, 119, 80, 62, -48, -55, 110, -10, -42, 5, -2, 64, 61, 56, -40, -35, 107, -104, -40, 125, 24, 2, 30, 110, 102, 82, -72, -44, -47, 48, 50, 79, -79, 16, 21, -99, -82, -23, 97, 74, -2, -63, 71, 63, -17, -78, 112, -108, 36, -14, 78, -54, 44, -11, 22, 3, -109, [...]
- b[157] = new byte[]{70, -78, 85, -60, -126, -88, 13, 123, 66, -66, 37, -116, -65, -12, -105, 48, -18, 54, 14, 126, -108, 88, -30, -125, -53, 104, 97, -40, 4, -105, -78, -60, -12, 123, -31, -70, -101, -79, 117, -37, 125, 34, 37, 105, 68, 55, 76, 1, 71, -54, 126, 6, 84, -35, 6, 20, 43, -97, 110, 116, -9, -61, -9, 43, 94, -85, 6, 102, 105, -49, 15, -7, 118, 103, -84, 32, -100, 97, 96, -10, -116, -32, 104, -102, 58, 12, -19, 22, 59, -110, 113, 56, 36, -103, 93, 9, -105, -5, -39, -11, [...]
- b[158] = new byte[]{-77, 46, 45, -26, -79, 64, -17, -111, -111, 4, 79, -125, -87, -81, 108, 67, 24, -49, -106, -30, -83, -4, -103, -60, 99, -98, 32, -72, 121, -54, -87, -57, 38, -57, 113, -58, -117, 34, 116, -115, 64, 62, 122, -34, 23, 59, -59, -32, -21, -36, 2, 3, -36, 85, -60, -106, 80, 47, -67, -13, -13, 73, -107, 124, -121, -8, -36, 114, 10, 59, 24, 49, 79, 98, 35, 27, -79, 10, 48, -32, -1, -85, 30, -115, -100, -60, -17, 123, -128, 107, -54, 8, 11, -75, -78, -48, 81, -28, 95, [...]
- b[159] = new byte[]{102, -49, -63, 124, 90, 22, 34, 102, 26, -69, 103, 89, 45, -66, -55, -99, -25, -109, 66, -98, -20, 67, 78, -78, -94, 113, 42, -47, -122, -72, 4, -45, -119, 27, 47, -7, 116, 97, -8, -38, -116, -19, -48, -6, 79, -40, -122, 127, 75, -97, 23, -19, -21, 21, -127, -50, -93, 3, 92, -73, 5, -52, 99, -36, -61, -24, 14, 52, 9, 73, -111, -59, 18, -44, 119, 27, 125, 83, -15, -31, 121, 58, -109, -43, 11, -121, 112, -10, -49, 92, -106, 89, 76, -45, -101, 111, 113, -23, -84, [...]
- b[160] = new byte[]{-123, -41, -125, 38, -28, 103, -103, -65, 42, -12, 70, 30, 115, -49, -97, -70, -44, -1, 10, -6, -95, -90, -86, 20, 118, -39, -122, -24, 77, -11, 70, -74, 9, 14, -49, 122, 51, -107, -97, -98, 15, 116, 32, 74, -85, -99, -58, 94, -30, -75, 88, 14, -121, 17, 100, -83, -73, 118, -6, -83, 37, -93, -31, 77, 64, 87, 94, 30, 54, 35, 35, 37, 82, 122, -24, -21, -46, -120, -5, 78, -7, 22, -10, 24, -62, 5, 90, 81, -35, 116, -81, -79, 49, 88, -50, 89, -20, 48, -112, -37, 31 [...]
- b[161] = new byte[]{10, 80, -126, 58, -3, 38, 15, -33, -1, 45, 29, 14, -118, -63, -33, 106, 108, 92, 78, -7, -91, -64, -62, -32, 0, -124, 45, -34, 22, -50, -115, 19, -28, 95, 1, 32, 104, 60, -49, -46, -18, -117, 55, -64, 77, -63, -45, -107, -61, -30, -31, -83, -68, -52, 35, -52, -48, -52, 123, -24, -18, 97, -113, -111, 2, 2, 121, -24, -90, -1, 31, -79, -104, 99, -48, -74, 101, -89, 95, 16, -106, -120, -67, 110, 127, -1, 30, 71, -107, -82, -53, -47, 43, -14, -55, 19, 7, -54, -58, [...]
- b[162] = new byte[]{22, -49, -128, -104, 80, -89, 82, -65, -30, -101, 15, 3, -48, 106, 77, -119, -46, 15, -10, -84, 22, -13, 36, 64, -50, 107, 106, 61, 47, -81, 79, -87, -7, 83, -122, 5, 65, -54, 96, 111, 57, -21, 96, -18, 19, 62, -87, 21, 23, 106, 51, -42, 106, 96, 45, -126, 32, -57, -5, -74, 94, -54, -19, -106, 49, -105, -29, -94, -33, 99, -61, -78, 80, -10, -80, -29, -9, 90, -33, -60, 6, -98, 10, 8, -107, 45, -100, 55, 77, 92, -128, -35, -34, 125, 40, -52, -106, 118, 69, -93, [...]
- b[163] = new byte[]{-62, 3, -72, 13, -47, -103, -53, -40, 53, -36, -117, -114, -122, 66, 70, 37, -60, -24, -56, -69, -126, 5, 89, -67, 79, -9, 60, -87, -114, 13, 58, 23, -107, 83, 83, 86, -38, 15, 44, 60, -118, 62, 70, 33, 44, 73, 36, -4, -77, 30, -66, 38, 31, -64, -2, 70, -126, -59, -117, -55, -12, 43, 32, -100, 24, -39, 48, -59, -111, -79, -35, -4, -36, 118, 64, -96, -101, 100, -57, 2, -81, -54, -121, -105, -49, 48, -2, -90, -31, 111, -88, -92, 1, 16, -86, -27, 4, 76, 31, 125, [...]
- b[164] = new byte[]{18, 69, -19, -45, 100, -102, 69, 66, 35, 22, 106, 11, -57, 35, -70, 55, -24, 34, 47, -120, -128, -31, -10, 52, 19, 22, -88, -6, 104, -32, 17, -10, 126, 90, -2, -80, -9, -111, -105, 28, 18, 53, -58, 86, 12, 84, -71, 14, 114, 123, -67, -99, -21, 28, -67, -59, -48, 31, 67, -85, -88, -65, 110, 126, -118, -60, 81, 49, -109, 74, 13, -100, -117, -82, -26, -32, 106, -16, 2, -68, -116, -53, -18, 94, 82, -114, -5, 67, -111, -87, 88, -89, -20, -125, -55, -61, 108, 63, 26 [...]
- b[165] = new byte[]{58, -32, 106, -57, -110, -59, 38, -70, 17, 108, 57, -8, -41, -18, 26, -52, 81, -27, 42, 12, 58, 108, -56, 27, -79, 17, -102, 43, -43, 39, 62, -8, -71, -59, -7, -107, -31, 34, -48, -39, -116, -56, -122, -118, 70, -117, 81, 121, -20, -66, -81, 42, -23, 26, 91, 69, -27, 22, 79, -59, 127, -108, -35, -28, -125, 2, -19, 79, -92, -67, 114, -91, 127, -57, -58, 32, -124, 60, 21, -95, -56, -46, -10, -56, 95, -49, 78, 38, 80, 106, -108, -128, -86, 126, -44, -115, -119, 8 [...]
- b[166] = new byte[]{72, -17, -17, 14, -54, -103, 13, -46, 38, 57, -47, -11, -10, -58, 72, -20, 85, 21, -122, 92, 117, 16, -115, 23, 70, -65, 0, -83, 59, -128, 27, -111, 124, 44, 50, -69, -24, 23, 45, -40, 46, -33, 93, 53, 40, -62, 41, 87, -100, -107, -95, 67, 27, -37, 26, 43, -91, -111, 65, -110, -71, 88, -43, 63, 93, -77, 105, -49, 91, 74, 20, 105, -81, 82, -9, -71, -57, 94, -18, 125, 95, -9, 47, -51, 112, 114, 66, -63, -38, -109, 46, -82, -47, 99, 40, 8, -75, 14, 41, -91, 1, -9 [...]
- b[167] = new byte[]{-75, -110, -1, -88, 0, -116, 59, -44, -77, -102, 2, 97, 89, 3, 44, 108, -88, 4, -26, 83, -64, 17, -68, 103, -36, -44, 123, -25, 78, 34, -106, 0, 43, 71, -56, -5, -70, -3, 74, 23, -114, -82, 67, 40, -21, -112, 73, -14, 6, -118, -26, 96, 31, -6, -100, -79, -91, 30, 27, 122, -40, -124, 31, -76, -58, 31, -26, 1, -23, 28, 87, -45, -66, -23, 17, 40, 95, 59, -37, -52, -120, 96, 0, 24, 28, -12, 63, 90, 49, -13, 29, -43, 82, -87, 66, 106, 23, 102, -68, 68, 78, -110, -6 [...]
- b[168] = new byte[]{25, 23, -69, -72, 93, 112, 31, -97, -5, -44, 29, -17, -104, 97, 126, -92, -35, -57, -12, -14, -114, -42, -46, -16, -78, 118, -12, 15, -113, -49, -101, -77, -18, -28, -96, 30, -32, -25, -34, -106, 71, -59, 32, 24, 50, -114, -22, 25, -82, -105, -124, -112, 102, 103, 111, -22, -97, -8, -87, -5, 42, -35, 97, 15, 6, 43, -4, -58, -3, 123, 11, -80, 57, 123, 27, 34, -110, -48, 50, 7, -31, -48, -114, 87, -80, -6, -42, -95, -57, 110, 87, 57, -2, -69, -9, 38, -35, -54, - [...]
- b[169] = new byte[]{-16, 16, -59, -69, -19, -67, -106, -101, 101, 25, 40, -36, 101, -18, -32, -123, 102, -108, -128, -116, -37, -71, 74, 76, -27, 112, -59, 110, -46, 85, 64, -15, 29, -35, -80, 4, -47, -63, -111, -107, 1, 61, 18, 18, -105, -117, -110, 127, 34, -55, 24, 54, -76, 55, -25, -69, 65, -124, 15, -108, 52, 51, 87, 10, 38, -45, -40, 6, 70, -89, 53, -128, 115, 1, 58, 116, -1, -75, -32, 91, -111, 47, -111, -79, -86, 31, -19, 122, -29, -40, 42, -66, 72, 34, 126, -52, -35, 38, [...]
- b[170] = new byte[]{-78, 35, -46, 92, 62, 46, -33, -91, -104, -75, 59, -17, 15, 52, 101, 20, -8, -82, 100, -55, -47, 115, 58, -53, -35, -32, 53, -25, -34, 121, 36, 48, -100, -21, -11, 118, 10, -5, -70, -101, -15, -49, 59, -94, 113, -94, 12, 78, -47, -90, 19, 103, -101, 94, -115, -128, -50, 33, -104, 1, -53, -115, 3, -127, 70, 76, -88, -14, 118, 34, -106, 35, -78, 101, 27, -114, 50, 84, -14, -17, -50, -89, 8, 76, -94, 126, 118, -26, 109, -17, -48, 70, 37, -65, 40, -10, 66, -99, -2 [...]
- b[171] = new byte[]{-5, -3, 120, 62, 113, 80, 85, -98, -63, 76, 114, -108, -66, 68, -19, 70, -74, 18, -19, 105, -49, 52, 62, 96, 103, -106, -14, 50, 21, 43, 12, -71, 9, 107, -91, 15, 5, 94, -13, -46, 122, -61, 50, 39, -60, -93, -9, 80, 125, 74, -73, 18, 48, -94, 27, -84, 70, 86, 26, -44, -68, 12, -32, -58, -93, -112, 101, 53, -75, 99, -38, 125, 51, 66, -106, 91, -31, 52, 94, -16, -112, -90, -111, -59, -90, -29, 42, 23, 91, -40, -80, 93, 14, 15, -96, 12, -120, 79, 73, -76, 105, -4 [...]
- b[172] = new byte[]{-33, 82, 53, -115, -81, -127, -7, -86, 41, 42, 76, -19, 27, 50, 88, -68, -111, 22, 2, -56, 114, -96, 0, 21, -25, 43, -34, -32, -71, -49, -46, 71, 72, -103, 68, 26, 84, 68, -46, -70, -114, 66, 12, -122, 43, -17, 51, 60, 48, 32, -11, 121, -125, -23, 46, 39, 38, 26, 112, 62, 11, -35, -69, -93, -44, 6, 1, 82, -9, 114, -45, -65, 12, 37, -95, 54, 41, -42, -20, -39, -98, 96, -125, 62, -93, -121, 98, 40, 25, 3, 62, 49, -26, 73, 102, -66, -98, -82, 39, -81, -24, 14, 10 [...]
- b[173] = new byte[]{93, -76, 95, 14, -95, -98, -35, -25, -120, -42, -47, -15, -15, 73, -49, -99, -32, -63, -25, -77, 124, 85, -28, -110, -51, 124, -43, 8, -44, -96, -60, -31, 31, 119, -89, 127, -70, 126, 66, 15, 17, -58, -6, 110, 48, -34, -46, 27, -75, 41, 50, -31, 29, -66, -52, -63, 126, 75, -105, 17, -67, 51, -80, 103, -5, -34, 122, 6, 45, 44, -92, -15, 3, 73, -107, 121, -43, -117, 22, 71, -31, -2, -2, 13, -128, -14, 126, 52, 69, 62, 115, 41, 91, 73, 38, 75, 1, -32, 104, 124, 5 [...]
- b[174] = new byte[]{-116, 97, 35, -4, 6, -127, 121, -10, -100, -10, -29, -100, -104, 107, -114, -10, 113, -2, 55, -20, -52, -80, 46, 42, 1, -18, -103, 80, 67, 12, 33, 119, 83, 26, 116, -106, -105, -75, -19, -45, -7, -54, -85, 35, -93, -35, -111, -10, -29, -47, -16, -112, -97, 27, -97, -112, -66, -47, -68, -50, -91, 13, 94, 3, 115, -15, 18, -82, -111, 124, -93, 43, -116, 114, 79, 38, 100, -39, 94, -76, -124, 73, 56, -33, -113, 122, 13, 45, 79, -62, -86, -96, -50, -87, -33, 51, -99 [...]
- b[175] = new byte[]{68, 12, -51, 11, 25, 79, -39, 47, -4, 45, -10, -58, -74, 84, -125, 74, 26, 49, -15, -60, -96, -104, -109, 14, 115, 108, 79, 22, -49, 30, -127, -107, 73, -117, 9, 102, -99, 45, -38, 5, 98, -113, 69, -74, -15, -111, -104, -107, 85, -119, 110, -32, 99, 73, 55, 6, -24, 113, -50, -99, -126, -71, 118, -16, 117, -64, -79, -120, -92, 19, -100, 48, -95, 13, 76, 120, -30, 86, 83, 124, -13, 22, 38, 4, 54, 30, -46, 44, 20, 31, -115, 83, -48, 30, -25, 28, -74, -65, 15, -23 [...]
- b[176] = new byte[]{-45, -56, 102, 102, -101, 65, 24, -94, -86, 71, -92, 51, -12, 99, 92, -39, 105, 53, 122, -40, 20, -4, -86, 32, 110, 35, -48, -104, 8, 121, 33, 121, 83, 5, -49, 123, 14, -31, 19, -96, -66, 1, 111, -49, 61, -99, -13, -101, 85, 15, -42, 122, 89, -94, 9, 47, 48, 18, 52, -127, 118, 105, -27, -110, 69, 59, -3, -66, 84, 79, 115, -8, -109, 90, 65, -23, -100, 79, 31, -44, 37, 118, 62, 90, 107, 57, 0, -1, 32, -101, -46, 76, -61, 124, -103, 92, 116, 83, -95, -43, -32, 28 [...]
- b[177] = new byte[]{-48, 104, 107, -127, -76, -110, 28, -14, -42, -73, 36, -74, -102, 116, -79, -84, -48, 35, -3, -36, -85, 21, 7, 49, 34, 3, -29, 79, -65, -69, -15, 38, 117, 101, 49, -100, -45, 123, -20, -102, 86, 120, 103, -10, -50, 59, -50, 4, -9, 34, -101, -107, -94, 57, 117, 33, -43, 94, -68, 121, -20, -67, 36, -118, 66, -4, -74, 2, -126, -80, 9, 20, 52, -19, -27, -1, -116, -17, -28, 87, -62, -83, 20, -32, 27, 30, 44, 21, 49, 65, -44, -45, 92, 45, -52, 26, -126, 75, -59, -51 [...]
- b[178] = new byte[]{-39, 81, -94, 49, 95, -33, -38, 19, 89, 2, 60, 55, 125, -41, -121, -57, -4, 17, 33, 92, -34, 63, 77, 124, -107, -100, -89, -49, 4, -78, 72, 111, -13, 64, 28, 114, 70, 104, -73, 98, 98, -107, 102, 104, 119, 104, -101, -89, -70, 42, -90, -67, -37, 116, -112, -98, -91, 95, -77, 60, 5, -88, -40, 28, -16, -127, -110, -94, 78, -57, -54, 15, 39, -14, -75, -96, 0, -15, 86, 9, -38, -67, -98, -67, 116, -90, 43, 75, 47, 127, 62, 110, -84, 31, 24, -59, -83, -44, -77, -11, [...]
- b[179] = new byte[]{-120, -60, -126, -121, 89, -71, -67, -53, 119, 11, -78, -60, -97, -100, 10, 69, -117, 90, -105, 59, -58, -22, -110, -102, -124, 109, 125, -83, 54, -6, 103, -38, -69, -7, -69, -125, -80, -62, -7, -56, -50, -115, -88, 59, -24, 87, 27, 119, 14, -2, -54, 71, 7, 82, -33, 17, -65, 63, 38, -5, 108, -111, -81, 67, 102, -72, 22, 20, 103, 77, -82, 7, -68, -5, -27, -35, -54, 73, 116, -56, 2, 10, -5, 23, 121, 117, -24, 48, -66, 41, 31, 49, 101, -92, -3, 27, 54, -61, 40, - [...]
- b[180] = new byte[]{-124, -34, 62, -57, -5, 10, -12, 84, 89, -97, -103, 101, 107, 14, -1, 92, 49, -80, -122, -35, -63, 112, -116, 64, 20, -2, 9, -96, 106, -107, 64, 44, 60, 115, -110, 14, -107, 42, -118, 16, -27, 98, 98, -53, 53, -102, 123, -28, -93, -87, 21, -83, -51, -94, 48, 64, 60, -121, -60, 108, -80, -98, 29, 36, 26, 69, 13, -97, -37, -111, -24, 66, -54, 20, 38, 90, -101, 41, 102, -48, 47, 68, -34, 125, -102, 62, -89, -57, 68, -127, -126, 86, 6, 113, -61, -14, -82, 125, -34 [...]
+ /* These strings were generated from random byte[] arrays fed into commons-codec-1.3.jar */
+ private static void initSTRINGS() {
+ final String[] s = STRINGS;
+ s[0] = "";
+ s[1] = "uA==";
+ s[2] = "z9w=";
+ s[3] = "TQ+Z";
+ s[4] = "bhjUYA==";
+ s[5] = "1cO9td8=";
+ s[6] = "sMxHoJf5";
+ s[7] = "jQcPlDsZzw==";
+ s[8] = "TAaPnfW/CYU=";
+ s[9] = "cXTZuwzXPONS";
+ s[10] = "Ltn/ZTV4IjT6OA==";
+ s[11] = "6fh+jdU31SOmWrc=";
+ s[12] = "E/5MoD4qCvDuTcFA";
+ s[13] = "2n9YyfCMyMXembtssQ==";
+ s[14] = "qBka3Bq6V31HmcmHjkY=";
+ s[15] = "WvyZe6kQ8py7m25ucawJ";
+ s[16] = "oYpxMy6BSpZXhVpOR6dXmA==";
+ s[63] = "yexFaNKaP+VkVwEUvxQXbC0HSCi/srOY7c036lT25frs4xjIvp214JHCg7OL/XZW3IMe6CDgSMCaaI91eRgM";
+ s[64] = "vkqgnuJ3plxNtoveiMJuYLN6wZQLpb3Fg48/zHkdFuDucuMKWVRO/niFRgKsFqcxq6VgCxwQbePiP9sRnxz7wg==";
+ s[65] = "YHks3GCb2uVF47Y2tCieiDGJ879Rm5dBhQhQizYhfWOo+BrB2/K+E7wZWTid14lMpM60+5C0N9JNKAcBESeqZZI=";
+ s[66] = "z8551jmQp/Qs95tw226+HCHWruKx/JvfBCfQ5p0fF77mkSpp66E552ik2gycrBBsMC/NbznAgTZoMzZxehfJwu49";
+ s[67] = "VsR2whqq/qQm342+TNz1lgOZMoWbpCz+kj2zflq0nx7S/ReEVPUJcqgMtVzrr2FVQPfBAH5VRjR+hkxwv4bssQms8Q==";
+ s[68] = "5xmIp8dUJZzkisIkuEPsnPXvzDeMo48qWFfHIn2av3jr5qoZHCs0LfNEyepC3v2sa0nCU0FlqsmDyTI5/2jt5zsLtV0=";
+ s[69] = "tGEgXjglUB9NbCtiS88AetLtRqhCAnhzOUKVgvbJZHqOA6x8uOorA1t3NcaIA00ZqbPYALu4LzIm4i4lAL9QgiH/Jg7b";
+ s[70] = "gFtxEhYJahDmU5dpudYs6ZTsqAx+s2j+06A0zeyb3U7nhZFsbkCDlds0EYUoqerZqZPm7F6CDOOD3dU7nYmelE0DxyMO9A==";
+ s[71] = "j/h/1JygYA5bjttxzQxr5gBtgh+AYVozhF4WgvcU/g49v0hUy6FdhfZewGK+Phtzj7RabI5p2zXyzvkmLQdFhdI5Um4O5sw=";
+ s[72] = "m+kYVGojIR5pgbz7pGJm2g+3qqk7fhl3cowa2eVrhki7WofyywnRezqTxOkBgVFz6nKs8qxpbbbzALctcPeMsp9dpXUfuUJr";
+ s[73] = "pPaGnMr0UYmldnJVk/F+3WCJJ1r2otvD5KJdt2u1RnS6LwhHhwLCqfW8O/QEg43WdxKomGL/JM33tn/B9pMPoIU0QTGjq2GRow==";
+ s[74] = "mOxzGyym6T/BxCV5nSiIYMlfAUmCN7gt7+ZTMg1kd8Ptirk+JF5dk8USbWBu/9ZvNg5ZuiJCeGwfaVpqpZ3K9ySF7C87Jvu1RUE=";
+ s[75] = "VYLOIE4DnhxJn3FKS/2RHHHYLlZiGVdV/k4uBbtAYHUSTpRzaaYPGNAVjdNwbTHIihmeuk/5YQUy8NFsxIom+Li7bnWiBoHKBPP7";
+ s[76] = "7foMpJ0TknCatjUiSxtnuKSiz4Qvl/idWY9UKiTljoQHZ+C8bcUscnI/bZr13e6AvyUh47MlpdGvzIm05qUdMWWLoZJOaGYvDmvrWQ==";
+ s[77] = "jxQSGiFs+b1TfE4lDUAPUPJ0SWeUgl03rK6auieWJcarDIHM97gGOHMmyHudRMqkZmIkxYRgYgCCUg/JeU91OZD3tL4U+wNhShywe88=";
+ s[78] = "UGmH/gl7t3Dk801vRhRDEbgsfShtHZ1gZQn4KNZ5Qsw3WiGjW0ImInVHa+LSHBzLUjwC0Z3nXO4i4+CiKYqAspOViE6WqVUY8ZSV0Og4";
+ s[79] = "wdEoYmJuRng2z2IkAiSgJ1CW2VE7H7oXpYWEFFO8nG0bZn7PHhT8KyhaO2ridl8eUEysja0VXFDyQqSgZnvdUKrCGepWGZbw0/0bDws3Ag==";
+ s[80] = "5kZqgrUbt+rN5BWAddeUtm9TGT43vYpB6PeyQwTyy9Vbr0+U/4Qzy0Iw37Ra293HmkmpgQzuScVpcIiFGXPAFWwToR+bovwu7aXji/FnMwk=";
+ s[81] = "E467MMmJbmwv8Omc2TdcyMr/30B8izWbf+CAuJtw67b1g9trhC6n4GYnXjeW9DYvmWoIJPx0zvU/Q+gqv0cteg2bx9P2mrgMDARb6egowqjx";
+ s[82] = "Vpt8hYb4jx1F+7REX7K65v6eO5F1GDg/K8SVLWDSp0srupYEQkBVRxnB9dmhSo9XHpz4C8pRl8r82fxXZummEf4U2Oh0Dip5rnNtDL+IJvL8lQ==";
+ s[121] = "hf69xr9mtFf4N3j2uA9MgLL5Zy94Hjv+VQi94+LS8972JJgDHCQOwP5whdQkV+SJpXkiyHGaSsQ4fhepPwzuZcEpYER+beny1j+M0HSZe36MdRIhlTqno+4qsXckL0CjXsYkJJM0NAfOYjHAus5G1bgi9VhmiMfAMA==";
+ s[122] = "yKzTh5hPp9/PBeZtrZXsFHAR9ywOM3hRaBDkgG9E09wFW8MZD0xMGegcp0QrTJcP8QYOaYhTDVimPqsNTVOmjdjkvS+2WhjJW4mVOXQ8KID91yaBtPo+DStL5GMgctcP5MoVf1Vp8w/mYtofqbllfDm5NfYzh2A7ijY=";
+ s[123] = "csFmwvDzoO4IO6ySDA4B2V7emEetAwCgO66zzlfWb3KDrPfFZc3Jgr4+dlaUkEIDHYeLHETdTssWOl2KrPHBEsULpDTR+3OhurXb1Qr2NvHiHFuqT3Geb6EYw2albfTmXxch82ablt4WKl4qPcSey54v6tsCuUuZzrkt";
+ s[124] = "5InxvKwpoCV7EK78OzU/tL9/NmK14Prw9tOCAyK+xpUNLZriuVEVdgpoZ05rliufaUDGHH8dPAem8G9DN/VOPktB6vXKtc2kMUgnMTiZwv/UVd+xyqnT8PLEdNQ8rCWxyiCcLdXFf0+xcE7qCcwzC+D7+cRW+i6dnpZkyw==";
+ s[125] = "cEx7oTsSHWUFPj92cstdy5wGbRcxH+VRWN8kaNTTCPWqSckyU9Xk/jj5/gj9DFwjfsCSp60xutf4/rFanjtwqtRg6dJLP4JAgpOKswDlHi6Vt7zF/w7HidMf2sdtlsqzayZmT2Hn7iOo3CExzr5Z5JfmMFAX8R9peUN4t5U=";
+ s[126] = "AeXetVbj+7mmGiCs3BGUSZDLlq2odMsN8JAHQM64Cly8y5jw75PpISocWRFFQmmXYP7ckKmtuhIvD69HtZxGhNRsl1l1gXzKFhsWykcRtG87F8sS1Uv/i6QvGiRIDVEGGIzWrzRIISkBb9wCxJ2HESfleWwrz/GqryjoN26B";
+ s[127] = "aj1/8/+U8VO3D2iAwvQXZ4H0KwtuzDm4JCC8+22ccqk+UzKvqjGs87XngwfsMfSkeGVAi6VB6tfNJTjYctaj7R8dwh2PIfLSrvaphw4wNB2REjplnPojoOb9bNUNtUvdK3b1bArOWugIRJWLnMl72yEHFb1iBfBmn7uIa7KT2Q==";
+ s[128] = "kiMuF/1CMRlgoS/uLKn1mNZFZNHJNkRQnivOrzj8HQAagwzvTXvsGgI9hXX3qaeZL9/x/Oq+Y5F6Dh+wXo+0kp6JagFjvbTJcQSowFzIwg7/V9sans0NE0Ejow5BfZKvihFI46sHiALl1qzoXqLQq+5fZGIFRyyY8wFW1uiNu9k=";
+ s[129] = "YXmCWhiNz4/IhyxQIYjgNvjX+XwDiPTSBMaFELm5X8Y4knGRnkF4/zix8l9wHBb+7Cgfrr46rF7eiIzaAFLjLjjewy63duBJiVbEWjqFO0fu6T9iIjuEaF2sTppvuZNPHx80vN+HLAnAVmgFESw5APXWn15dizvuUfVHd5isCqbA";
+ s[130] = "GJfUoBivW5uqDpUxTRfjGWNYfN3/dTFtdRqCIH5L2c1nWX0dgY3ba1+fW/YX1Oh5aw4lC6BIiiThjJoV1VrNnlXzbcUcMy+GsDUUB8Qe8lBvfe/t4RmNPB0hVgrS89ntbuU0SsCmWw+9DqM3nidPebANKERig1zZTBBKgpVf7HPFCA==";
+ s[131] = "eTerNs7dOqJAxAxcMQRnUDc2cBj2x0jU1g1D3G+b22kDz7JBzOy/mxhGXAQ3130lavWMhImSBkReU+z0A13EYVMUv9PFzD747KCvns+SCo52YNHB0896b4l47q8hu8jsD17TZ2uWWJhS4cNnSE1jeM6NoXGKvf90yxfzwucNYc4RdaQ=";
+ s[132] = "lbrGsjbzE521q8tzVHV7vcTPchUnzI/UfeR2R+cmOa29YljPWLht9Wx2JrjiKv4Of5nXe7kvhi+LYUuFVqgaqIFhC/PLbqOFiT2VZcXorToaRT9CLiqV5b6nHN/Txz6SI7MiD3hnk7psDbglPOo+ytqc9sFHj7UkR1ZctQjwFYwJjlxf";
+ s[133] = "mQwAPzYzfxz9FXEiZ6M8u1oN3EJbFYmNVfpm+j0DqgU+OPI4URHBIrF4xvdMvAPn0WuarbQy/ZVN0eKL7S4K3Mvan0flAwaZdI+e5HpkfxOoGTp8Dk5EFTXjmZ/s+GonePEQEGNVPL1WYoD6xXqAAvMLKtyrFcpoiGS9eDBlsZDQzPzz/g==";
+ s[134] = "3G6d12UY4l5W7Nnw0BL0HnViVg9SdEuLMqeZwy0RlJR/Ytcgd/mIxIuXXAlGhvhoX6Xc2BGU7RpTi1jYKzA86yul0j96dbcE4OtrP9lUBJlcY9eWz59dvLqKxwt3cEOBwrPf69MHuIa256es3AOCobfC8RQScW0PQ0QUa1VHB/eXSsVTSWg=";
+ s[135] = "AxgrZKTFk5JvLC3DBACHwp266FxKI/yn9F+1tYkzL57RVs5HCJYS47VuG0T0E2wqzHqcLKPQMZWU7vbRoyMGNL3ZtaHoZqTqcq9KWtODC+OnEvSS7+1P4SmQDuyL2MJ/eJABJKNcu1K/Lk0buAaO0FvX6OGBcPzu1+dv/ZkwuORK07qRnxqQ";
+ s[136] = "atkG8l2U/Nnm+zLu7zjenrfcAVQJMUqHimFZ3cQfaUp4qyrFn1UiwZ33j66Vt63eVaT/FXx+LlEnsHn6ATPBMp3iEYoBJYyNpjz/zROhBbcznQAMdWUTcyKInvnG3x6ExgBXpyqfxxp/Pm8by7LlSUT5MKHdcu+TEfUXRokCr2iPnt7NYsNDfA==";
+ s[137] = "dciU1mSHGcBxOAVBgJx75J6DaQdBZfTIzQ04WhkkdRMupOZWSnv19xhz8hiO+ZnbBtDJuO5rHsUGzH/jYacfZyCQ924roRvkh3T1yxsLq3abZJUCD9HYnPTELVhv1+cEF4aoO3vGOu2FpfLUn5QTd0PozsIqcqZVB2V57B7DjfizUe3D8Yf5Vco=";
+ s[138] = "dgR1PPacBvtILBmg33s9KWtuc67ndh3rCHZ/lIN7sENgbFqJQy5DC3XIeHTV7oWd+tJQaXxoC71/SU7Rz6OClAMKXLbMz8U6RPiqn3M7MRCQcDfNjA5cCNknXT9Ehz/IZF/7lcWrwxBKYm4B98lPkpZtR2QHndiQ3venzWrP0P5y27mReaFuaJ++";
+ s[139] = "1Q8rfp1HuGsxurTgGMakxj5SwNF7EixXxVPnfGADWDcygh5C1BMXqiL1AuVXOVFOsaydfLWGC8Kbh/JiL6H+12lYrNGUT9yJRIzRDi4XylMnrYwBtwCJjoHSi4exz5K2ih54utVAuzXZg6mnc9ied/mNRjj9d2HFD5mv0w/qTN/WFxEmtuZM/nMMag==";
+ s[140] = "w01TnPP/F3Vni3fBdV32Bnbb4J1FcbaE+Xn44no5ug77U8FS1gSm3LqJ8yTyXduzl5v2dwBEfziEfTuyqgeLLsCYTBjXmYOIHQosEl6DyAknu4XK52eQW+Fes9eSs2Nq+G4aaR4y4leeFNmCoZ9BQmAAZr0LFkqnvqaKmBVgcgxPs7/8SQHnpqvaU6Y=";
+ s[141] = "OfzIF38Tp5g1W5eVbrkrMe0Mm7e0wBYg5hVvLpn/5MW5OFcmRDuBp15ayRBnJ1sBI93+CNl0LwP8Q0z9IXFjTER5gHZ1KfG8NV+oacKNG7aYrbUftkSL/oPfRNPez6U0FuWgvVrXUB6cwKTWvwb9KoD7s6AGYRdH50ZgJdBniFD7dKoOQnJ/ECuTUXI+";
+ s[142] = "4hoX0sjqlkSJPUq627iJkNYRbtD+V2qErCuTikaeRDEZvVHWvzdvwj4W1xxJjz+yHAN6z2EjCWidcSsVgTejQ1bH8uTzJgh/zq3yGUSsJoJWrecqxsge8bEBjkm+qUO8G3kAnC6FMjJ2NYQeXf6OK6OgsqyJwlHPTyAms2/IoYTB4iEqgIFG/2fNEJEIag==";
+ s[143] = "M/dy14xNbZMRfHiKKFdmD/OrEB+8MexrRO8mMh0i5LrNA5WUtLXdwUfAysYmal94MSoNJfgmwGCoqNwlWZBW1kpQaPdqsrn2cvc6JcZW9FlOx07DERJGbZ6l6ofbzZWgF+yf+hvT6jnJvXBVCTT3lfO3qo4leNuEJwsuU6erXGC3Ch53uPtGIrdDUpcX6/U=";
+ s[144] = "GgLr2hd3nK64IZv0JksKAT/yJNQ38ayuWyBnWLjXbEmT048UDppsrrnP6hikRo5v2TlHGhD2dcwG9NLK3Ph8IoIo9Wf2vZWBB+SMI9FpgZxBWLEjwHbOWsHaEQMVsQfk38EWQP0Fr6VyMKlEQfpsRkuCpp1KxscaxK7g5BgXUlb0a2x0F+C9hEB0OVPsj4JN";
+ s[145] = "W9lKcLDqNGQAG/sKQNaRmeOUmLJ7GcMNqBaGZ659Rnjr6RTrfnmkp5Z9meALnwXoHjPjzSQDJnVYsY+xyMnuPgl6gMVAhAm+XprYVpsne4vt+7ojUqavVPBqLy5dtnhp1qfcnAiV5cZhHXX7NbxkUOzptjEGCQjnhSH4rPbZtgoIWE8Z6boF3l/thLnFX+AiiQ==";
+ s[146] = "iYLn5h9lIhD/x9moaPRnTX6mJEJKThg4WXxS7IrR2zblH26uOkINz0dJNTJVets0ZNYDnsnT7J2iI3Y6hTVWPGoYU49J3B2LhCREs0DZQ3C7080FtiOcfHbfBLNn0DyCK1LeAC7YB/bNdiyhLqH8fKl+0+KhiPDIUBJY2e7IbZR/9t0sxJbIXx6cRvI5AXex12o=";
+ s[147] = "SlRJEc7npTUvQq8SgBYKmVY/3wHYp2gsDxafN/JLUuEqEjmWMtW7fxASi+ePX4gmJJqLhD5t+AZxiCwYK3L3ceuJx4TiqVgJz8d6sc7fgWXluh1K+BcGPbZ7+Cq4Vsga7JEBVekviEZ5Ah4apNr8RkB7oMOUVPGxRcyyaVE4zBW+scA6c1yi/HQXddQ9rWyLUsVo";
+ s[148] = "AAlbGR6ekLOzx4hpqZTUqVUQ0FL2CFpgCMOp6CuuUzkSnWXpUjvOiSDkNPgoTPgpgmg3uYvMsX43mkPGUGC9awDThXyGQh6u3WfWtmhiPRqXnjFek+EPd0LYXps71non6C9m7nUlYNWzBJ1YzrzWjlB5LLPBN8bsZG6RbdZkYMxJ9J5ta/c30m8wDDNuTm0nEE0ZVQ==";
+ s[149] = "nWWbBhzObqwEFh/TiKREcsqLYbRjIcZflJpol16Mi4YDL6EZri22qRnTgrBtIY+HieTYWuLaCSk/B9WcYujoS6Jb5dyg3FQ6XF9bYaNQGx2w8DHgx0k2nqH/0U1sAU0kft32aD2orqCMIprbO1WJIt2auRnvcOTFoOax926nAkxvR3nrFVDevFjDbugpWHkGwic6G7o=";
+ s[150] = "WNk1Rn2qtG+gk0AEewrgo+aRbNrG4CgQpOR8Uo7c2m2XQY8MVDu4uRA6rzYGGdgqTcICKky9MvHeJeNWVAXOxmA4EdXQ2xItFJdQtxBt56cad9FBXXsz21yVsPr5d453abi7T3XfHVTToekiOlxAJs+bpat9cFRbIdHghO9wc/ucoArT53vpYsnyeVnmZG2PX48lXpNS";
+ s[151] = "wVmiO6mdf2aahrJlcmnBD0Qa58y8AvzXtJ54ImxgPLPn0NCQIrmUxzNZNTODE3WO6kZMECaT/REqT3PoOBp9stCHCFNXOM7979J44C1ZRU0yPCha00kQZBF5EmcLitVCz10tP8gG1fiIvMjwpd2ZTOaY4/g4NeJHLjJPll0c5nbH7n4v+1I+xG7/7k7G6N8sp21pbgpTYA==";
+ s[152] = "OoiVZosI+KG0EZTu+WpH7kKISxmO1zRYaSPMBMW0AyRiC2iZVEkOMiKn12XPqIDSW/kVA58cvv/ysTAzKLTu78Uo+sVcJe3AtLdgeA9vORFELTP4v9DQ/mAmehe3N8xk+VTLY6xHWi6f4j9cTDW/BDyJSDRY00oYoHlvnjgHo4CHBo0sMGgX3CwcnK2hpMFVtB/3qPl6v2w=";
+ s[153] = "97ZVsTYwD8VrgN1FOIRZ8jm8OMgrxG3o1aJoYtPVWXp9cjjlgXqTMZVsoWr3pr7pudw+LYo1Ejz3JpiUPHqWcZ2PWrWs7PR1akYGuwdCBHYvCGTcZYFe/yu1AB8w5zYsl1eJR45g0u1DlXfx5BUAUzc4yJDjc48Ls62bn8t0EJ7+30sWwifqKuz2EHpsqp1j/iMlwzKJGjGE";
+ s[154] = "0NSYKTvBKKInwL9PJ/pWUWVX4gjF3igsA2qqQMsRew0lI1LcCB18eGCYk0AnyUCe99w5lWHGFUMMeH6DZciAylWGeDn19JdzVOTevBWk3LIujI1GvsEB3oVqf2Zl9IZeDGCT4+bQKBWvgcXHjysZfnn/5z9Xz06qrPqac5LfS36fDcwnkrUYQWDsL2Ike32ALmOnkcDjNq1BoA==";
+ s[155] = "5ok+rYI4LCgGa2psGUN/fdkT2gQEToB9HRiFXQpe2YcQvEN2z7YlJCETx4jSWw06p5Y8tZcp08moKNYwUJ40DvPpGlDG+wUpFhC4kkfo6vj6TrCj5yoWJi5D+qdgH2T0JeWM80cYN0bsOsetdaqNhDONlYXZ2lVYkyVS/wzw8K5xX87EWktwOwFq/yYhuWCYJ9GZL7QuDipJjEE=";
+ s[156] = "KHzTalU9wPSnIjh5g0eHi1HUaFufxJpXpjDe0N3wEKINqbgzhbj3Kf4qWjb2d1A+0Mlu9tYF/kA9ONjda5jYfRgCHm5mUrjU0TAyT7EQFZ2u6WFK/sFHP++ycJQk8k7KLPUWA5OWScy1EO+dYF4d0r6K5O+7H/rpknxN6M9FlP8sH83DXK1Sd+UXL32D+4flF580FaZ5B3Tkx3dH";
+ s[157] = "RrJVxIKoDXtCviWMv/SXMO42Dn6UWOKDy2hh2ASXssT0e+G6m7F1230iJWlEN0wBR8p+BlTdBhQrn25098P3K16rBmZpzw/5dmesIJxhYPaM4GiaOgztFjuScTgkmV0Jl/vZ9eCXdEVNISeXkIixM4pssTFuUV7PY/Upzdj55rDKGLr1eT7AFVSNP30PhL8zZs8MANqKBeKBBDvtww==";
+ s[158] = "sy4t5rFA75GRBE+Dqa9sQxjPluKt/JnEY54guHnKqccmx3HGiyJ0jUA+et4XO8Xg69wCA9xVxJZQL73z80mVfIf43HIKOxgxT2IjG7EKMOD/qx6NnMTve4BryggLtbLQUeRfhriQeY7h65tD9ierhccXoXDpGnmBn9m2BQP78y+Qhc4eIsa3LcxbQJUIwvURjFp/rgMD7lhOLboa/2Y=";
+ s[159] = "Zs/BfFoWImYau2dZLb7JneeTQp7sQ06yonEq0Ya4BNOJGy/5dGH42ozt0PpP2IZ/S58X7esVgc6jA1y3Bcxj3MPoDjQJSZHFEtR3G31T8eF5OpPVC4dw9s9clllM05tvcemssLdcd85UP/xBaDrmpAl8ZDSc73zflK3nJw8e0HQFYntNnlZPFyyyBLHnLycb6Jlvq7F2OqrZR+FXZnL3";
+ s[160] = "hdeDJuRnmb8q9EYec8+futT/CvqhpqoUdtmG6E31RrYJDs96M5Wfng90IEqrncZe4rVYDocRZK23dvqtJaPhTUBXXh42IyMlUnro69KI+075FvYYwgVaUd10r7ExWM5Z7DCQ2x8Tm1meK2YCTPkF1VXXexl1UjYCnRQuQxppdophMwroJK8VqlJbFFslchTSBFuI7wgcdy+f/LHMbMsusQ==";
+ s[161] = "ClCCOv0mD9//LR0OisHfamxcTvmlwMLgAIQt3hbOjRPkXwEgaDzP0u6LN8BNwdOVw+LhrbzMI8zQzHvo7mGPkQICeeim/x+xmGPQtmWnXxCWiL1uf/8eR5Wuy9Er8skTB8rG4/ubb2ssvCkubObPAkMSOgFnX9UtxnCN4+nMNV2vvn4xMTSvvQyYWewfnlNkflTyva1epE9RVW2RqRtJikY=";
+ s[162] = "Fs+AmFCnUr/imw8D0GpNidIP9qwW8yRAzmtqPS+vT6n5U4YFQcpgbznrYO4TPqkVF2oz1mpgLYIgx/u2XsrtljGX46LfY8OyUPaw4/da38QGngoIlS2cN01cgN3efSjMlnZFo1x8T9p0Nn1IgRgevOd5ezVUL7WdY7eeiE1pXXcGBgDYn7NDQph0dC6HDlBiS95bDFcZ+6FYigE4WybpsOHL";
+ s[163] = "wgO4DdGZy9g13IuOhkJGJcToyLuCBVm9T/c8qY4NOheVU1NW2g8sPIo+RiEsSST8sx6+Jh/A/kaCxYvJ9CsgnBjZMMWRsd383HZAoJtkxwKvyoeXzzD+puFvqKQBEKrlBEwffXhLDoFQAW2ycYtBGztl0GsUtoOob2nv7ienx1xD6KNZNaxYx2ObRAYS/e8LS3pg5dku9MPBp1X12m8ZIXRAaw==";
+ s[164] = "EkXt02SaRUIjFmoLxyO6N+giL4iA4fY0Exao+mjgEfZ+Wv6w95GXHBI1xlYMVLkOcnu9nescvcXQH0OrqL9uforEUTGTSg2ci67m4GrwAryMy+5eUo77Q5GpWKfsg8nDbD8a3gUI/9EE0sCNp7tMaKwoJ56cxhbG3TJYpqWTpq3/S3q76x+3ETL+zxh6EMh8MJPfWcIxlDS7evKqdPgS00KgUtk=";
+ s[165] = "OuBqx5LFJroRbDn41+4azFHlKgw6bMgbsRGaK9UnPvi5xfmV4SLQ2YzIhopGi1F57L6vKukaW0XlFk/Ff5Td5IMC7U+kvXKlf8fGIIQ8FaHI0vbIX89OJlBqlICqftSNiVRxtaE+aCh0rBoDfgPwuC8qBC20I1O3ZLuKfeUVGkMOLEWeZLS6mmcn3cSERj9o/dEl8QYwQvhH+VG6YWF//yki1Vu8";
+ s[166] = "SO/vDsqZDdImOdH19sZI7FUVhlx1EI0XRr8ArTuAG5F8LDK76Bct2C7fXTUowilXnJWhQxvbGiulkUGSuVjVP12zac9bShRpr1L3ucde7n1f9y/NcHJCwdqTLq7RYygItQ4ppQGiP9jXf2Dn/qmVZZTh+SY3AZCIS+OVo2LAiYJHWnzzoX8Zt+dOYiOA/ZQKZieVJlc8ks+2xqYPD55eH0btZn5hzA==";
+ s[167] = "tZL/qACMO9SzmgJhWQMsbKgE5lPAEbxn3NR7504ilgArR8j7uv1KF46uQyjrkEnyBormYB/6nLGlHht62IQftMYf5gHpHFfTvukRKF8728yIYAAYHPQ/WjHzHdVSqUJqF2a8RE6SvvY+KSKWLMU3hjn1f6dqX599hYD7AnbPGTpFKDU5sLFOXbuynU1sPUhP+a4Hev9yNU6atLDo4CkX/Yq3FbpWVuQ=";
+ s[168] = "GRe7uF1wH5/71B3vmGF+pN3H9PKO1tLwsnb0D4/Pm7Pu5KAe4OfelkfFIBgyjuoZrpeEkGZnb+qf+Kn7Kt1hDwYr/Mb9ewuwOXsbIpLQMgfh0I5XsPrWocduVzn+u/cm3cr0Z11zsx0AZjTqvslACkDqiquY41JhtGdc22RCvIYom2l+zzMIMyCPsHeCSB1MBu8EWK3iP7SD3dWttwzMg0xanoPDgk0U";
+ s[169] = "8BDFu+29lptlGSjcZe7ghWaUgIzbuUpM5XDFbtJVQPEd3bAE0cGRlQE9EhKXi5J/IskYNrQ357tBhA+UNDNXCibT2AZGpzWAcwE6dP+14FuRL5Gxqh/teuPYKr5IIn7M3SbgOychZzLI7HGCvVhBUiJBu8orI3WmAIVcUhAsMGHsFveck/ZCXQA+Uq/WVnW1VNs6hSmIhsAFc51qsmsQK07z2Wptx4rRjw==";
+ s[170] = "siPSXD4u36WYtTvvDzRlFPiuZMnRczrL3eA15955JDCc6/V2Cvu6m/HPO6JxogxO0aYTZ5tejYDOIZgBy40DgUZMqPJ2IpYjsmUbjjJU8u/OpwhMon525m3v0EYlvyj2Qp3pwFKDkvncK3aNjN3KaaX6HuIy6kyqsDl0BTEnB5iJyHLRBCkeznTK019u48Yfsrz2oGuZcWzNj5/vKMdxQPiyJ9EHyox8Ark=";
+ s[171] = "+/14PnFQVZ7BTHKUvkTtRrYS7WnPND5gZ5byMhUrDLkJa6UPBV7z0nrDMifEo/dQfUq3EjCiG6xGVhrUvAzgxqOQZTW1Y9p9M0KWW+E0XvCQppHFpuMqF1vYsF0OD6AMiE9JtGnWs3JcaWP/XBF/CvhQlFGbHi3fbrD/haTEBnmpJWBgMdKribdbXHtBSFZ2MzCX2eDtxoDdRdEVGs4v/q8gVBS+WsnZ3TTF";
+ s[172] = "31I1ja+B+aopKkztGzJYvJEWAshyoAAV5yve4LnP0kdImUQaVETSuo5CDIYr7zM8MCD1eYPpLicmGnA+C927o9QGAVL3ctO/DCWhNinW7NmeYIM+o4diKBkDPjHmSWa+nq4nr+gOap4CtwL2wW2B5Yqt26pKgN9uAU5CmTL26hYFgMEOZfrkQ7XdYGy2CN8RJLmjeSFVVNBG/FTaK7tpuy0LQSkko6wczBYGeg==";
+ s[173] = "XbRfDqGe3eeI1tHx8UnPneDB57N8VeSSzXzVCNSgxOEfd6d/un5CDxHG+m4w3tIbtSky4R2+zMF+S5cRvTOwZ/veegYtLKTxA0mVedWLFkfh/v4NgPJ+NEU+cylbSSZLAeBofDvoJwnYKujN2KFa8PGAxr3Y8ry3qdkS8Ob1ZiHYAmLvKS9sGb/vjTvRy+a4Q7kOepsm7PYisinKelBAvDnjli6/lOutGrenjX4=";
+ s[174] = "jGEj/AaBefac9uOcmGuO9nH+N+zMsC4qAe6ZUEMMIXdTGnSWl7Xt0/nKqyOj3ZH249HwkJ8bn5C+0bzOpQ1eA3PxEq6RfKMrjHJPJmTZXrSESTjfj3oNLU/CqqDOqd8znTgN6nvnUdCeStLMh9bmWF1+0G11nDwg6GQWWQ0zjVDTq5j7ocXcFOyUcu0cyl5YDcUP0i2mA2JullInU2uBte7nToeSGB3FJxKueBbv";
+ s[175] = "RAzNCxlP2S/8LfbGtlSDShox8cSgmJMOc2xPFs8egZVJiwlmnS3aBWKPRbbxkZiVVYlu4GNJNwbocc6dgrl28HXAsYikE5wwoQ1MeOJWU3zzFiYENh7SLBQfjVPQHucctr8P6Rl7YL5wHc+aC+m92R3bnzm5rp1PeHm7uzy2iUUN0cgfbwJ4FrpXhVMTsAUpTbg1+037EWcGOuxir4dG2xBfgOwa+ejFHkw7y0LWRw==";
+ s[176] = "08hmZptBGKKqR6Qz9GNc2Wk1etgU/KogbiPQmAh5IXlTBc97DuEToL4Bb889nfObVQ/WelmiCS8wEjSBdmnlkkU7/b5UT3P4k1pB6ZxPH9Qldj5aazkA/yCb0kzDfJlcdFOh1eAcu5LvwTXOizmPwsDvJEnOkaDZrKESZshsHU2A6Mx6awk9/orf6iBlJHQIIH3l4o3b1gx2TNb/hUgdAlwtQDhvKO3skB0PS+rcWAw=";
+ s[177] = "0GhrgbSSHPLWtyS2mnSxrNAj/dyrFQcxIgPjT7+78SZ1ZTGc03vsmlZ4Z/bOO84E9yKblaI5dSHVXrx57L0kikL8tgKCsAkUNO3l/4zv5FfCrRTgGx4sFTFB1NNcLcwagkvFzde764DjYmj4YZhYsXSZCVKi0uu5M8fpgGDZ9UMSFR008cbhaIoFLWSANqiNJYSvTQZhGWfLtIPGLN+gIOMcaKhx1b5vg6OYSz6ScAM/";
+ s[178] = "2VGiMV/f2hNZAjw3fdeHx/wRIVzeP018lZynzwSySG/zQBxyRmi3YmKVZmh3aJunuiqmvdt0kJ6lX7M8BajYHPCBkqJOx8oPJ/K1oADxVgnavZ69dKYrSy9/Pm6sHxjFrdSz9TelUK9sgoFTWS6GxgzWEqXRBDDpGUnsNbSEcWLPKVLNNoYAcltY98JZaNSZBXcpa9FeSN7sVU43q2IEcDx3ZkJzRJpl/lb7n+ivMwX/OQ==";
+ s[179] = "iMSCh1m5vct3C7LEn5wKRYtalzvG6pKahG19rTb6Z9q7+buDsML5yM6NqDvoVxt3Dv7KRwdS3xG/Pyb7bJGvQ2a4FhRnTa4HvPvl3cpJdMgCCvsXeXXoML4pHzFlpP0bNsMoupmhQ0khAW51PAr4B165u1y5ULpruxE+dGx/HJUQyMfGhOSZ5jDKKxD5TNYQkDEY28Xqln6Fj8duzQLzMIgSoD8KGZKD8jm6/f8Vwvf43NE=";
+ s[180] = "hN4+x/sK9FRZn5llaw7/XDGwht3BcIxAFP4JoGqVQCw8c5IOlSqKEOViYss1mnvko6kVrc2iMEA8h8RssJ4dJBpFDZ/bkehCyhQmWpspZtAvRN59mj6nx0SBglYGccPyrn3e0uvvGJ5nYmjTA7gqB0Y+FFGAYwgAO345ipxTrMFsnJ8a913GzpobJdcHiw5hfqYK2iqo8STzVljaGMc5WSzP69vFDTHSS39YSfbE890TPBgm";
}
- /**
- * Tests to make sure Base64's implementation of the org.apache.commons.codec.Encoder
- * interface is behaving identical to commons-codec-1.3.jar.
- *
- * @throws EncoderException problem
- */
- @Test
- public void testEncoder() throws EncoderException {
- final Encoder enc = new Base64();
- for (int i = 0; i < STRINGS.length; i++) {
- if (STRINGS[i] != null) {
- final byte[] base64 = utf8(STRINGS[i]);
- final byte[] binary = BYTES[i];
- assertArrayEquals(base64, (byte[]) enc.encode(binary), "Encoder test-" + i);
- }
- }
+ private static byte[] utf8(final String s) {
+
+ // We would use commons-codec-1.4.jar own utility method for this, but we
+ // need this class to be able to run against commons-codec-1.3.jar, hence the
+ // duplication here.
+
+ return s != null ? s.getBytes(StandardCharsets.UTF_8) : null;
}
/**
- * Tests to make sure Base64's implementation of the org.apache.commons.codec.Decoder
+ * Tests to make sure Base64's implementation of the org.apache.commons.codec.BinaryDecoder
* interface is behaving identical to commons-codec-1.3.jar.
*
* @throws DecoderException problem
*/
@Test
- public void testDecoder() throws DecoderException {
- final Decoder dec = new Base64();
+ public void testBinaryDecoder() throws DecoderException {
+ final BinaryDecoder dec = new Base64();
for (int i = 0; i < STRINGS.length; i++) {
if (STRINGS[i] != null) {
final byte[] base64 = utf8(STRINGS[i]);
final byte[] binary = BYTES[i];
- assertArrayEquals(binary, (byte[]) dec.decode(base64), "Decoder test-" + i);
+ assertArrayEquals(binary, dec.decode(base64), "BinaryDecoder test-" + i);
}
}
}
@@ -407,35 +398,37 @@ public class Base64Codec13Test {
}
/**
- * Tests to make sure Base64's implementation of the org.apache.commons.codec.BinaryDecoder
+ * Tests to make sure Base64's implementation of the org.apache.commons.codec.Decoder
* interface is behaving identical to commons-codec-1.3.jar.
*
* @throws DecoderException problem
*/
@Test
- public void testBinaryDecoder() throws DecoderException {
- final BinaryDecoder dec = new Base64();
+ public void testDecoder() throws DecoderException {
+ final Decoder dec = new Base64();
for (int i = 0; i < STRINGS.length; i++) {
if (STRINGS[i] != null) {
final byte[] base64 = utf8(STRINGS[i]);
final byte[] binary = BYTES[i];
- assertArrayEquals(binary, dec.decode(base64), "BinaryDecoder test-" + i);
+ assertArrayEquals(binary, (byte[]) dec.decode(base64), "Decoder test-" + i);
}
}
}
/**
- * Tests to make sure Base64's implementation of Base64.encodeBase64()
- * static method is behaving identical to commons-codec-1.3.jar.
+ * Tests to make sure Base64's implementation of the org.apache.commons.codec.Encoder
+ * interface is behaving identical to commons-codec-1.3.jar.
+ *
+ * @throws EncoderException problem
*/
@Test
- public void testStaticEncode() {
+ public void testEncoder() throws EncoderException {
+ final Encoder enc = new Base64();
for (int i = 0; i < STRINGS.length; i++) {
if (STRINGS[i] != null) {
final byte[] base64 = utf8(STRINGS[i]);
final byte[] binary = BYTES[i];
- assertArrayEquals(base64, Base64.encodeBase64(binary),
- "static Base64.encodeBase64() test-" + i);
+ assertArrayEquals(base64, (byte[]) enc.encode(binary), "Encoder test-" + i);
}
}
}
@@ -457,45 +450,52 @@ public class Base64Codec13Test {
}
/**
- * Tests to make sure Base64's implementation of Base64.encodeBase64Chunked()
- * static method is behaving identical to commons-codec-1.3.jar.
+ * Tests to make sure Base64's implementation of Base64.decodeBase64()
+ * static method is behaving identical to commons-codec-1.3.jar when
+ * supplied with chunked input.
*/
@Test
- public void testStaticEncodeChunked() {
+ public void testStaticDecodeChunked() {
for (int i = 0; i < STRINGS.length; i++) {
if (STRINGS[i] != null) {
final byte[] base64Chunked = utf8(CHUNKED_STRINGS[i]);
final byte[] binary = BYTES[i];
- assertArrayEquals(base64Chunked, Base64.encodeBase64Chunked(binary),
- "static Base64.encodeBase64Chunked() test-" + i);
+ assertArrayEquals(binary, Base64.decodeBase64(base64Chunked),
+ "static Base64.decodeBase64Chunked() test-" + i);
}
}
}
/**
- * Tests to make sure Base64's implementation of Base64.decodeBase64()
- * static method is behaving identical to commons-codec-1.3.jar when
- * supplied with chunked input.
+ * Tests to make sure Base64's implementation of Base64.encodeBase64()
+ * static method is behaving identical to commons-codec-1.3.jar.
*/
@Test
- public void testStaticDecodeChunked() {
+ public void testStaticEncode() {
for (int i = 0; i < STRINGS.length; i++) {
if (STRINGS[i] != null) {
- final byte[] base64Chunked = utf8(CHUNKED_STRINGS[i]);
+ final byte[] base64 = utf8(STRINGS[i]);
final byte[] binary = BYTES[i];
- assertArrayEquals(binary, Base64.decodeBase64(base64Chunked),
- "static Base64.decodeBase64Chunked() test-" + i);
+ assertArrayEquals(base64, Base64.encodeBase64(binary),
+ "static Base64.encodeBase64() test-" + i);
}
}
}
- private static byte[] utf8(final String s) {
-
- // We would use commons-codec-1.4.jar own utility method for this, but we
- // need this class to be able to run against commons-codec-1.3.jar, hence the
- // duplication here.
-
- return s != null ? s.getBytes(StandardCharsets.UTF_8) : null;
+ /**
+ * Tests to make sure Base64's implementation of Base64.encodeBase64Chunked()
+ * static method is behaving identical to commons-codec-1.3.jar.
+ */
+ @Test
+ public void testStaticEncodeChunked() {
+ for (int i = 0; i < STRINGS.length; i++) {
+ if (STRINGS[i] != null) {
+ final byte[] base64Chunked = utf8(CHUNKED_STRINGS[i]);
+ final byte[] binary = BYTES[i];
+ assertArrayEquals(base64Chunked, Base64.encodeBase64Chunked(binary),
+ "static Base64.encodeBase64Chunked() test-" + i);
+ }
+ }
}
}
diff --git a/src/test/java/org/apache/commons/codec/binary/Base64InputStreamTest.java b/src/test/java/org/apache/commons/codec/binary/Base64InputStreamTest.java
index 422be5bb..4e45ad9a 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base64InputStreamTest.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base64InputStreamTest.java
@@ -50,105 +50,6 @@ public class Base64InputStreamTest {
private static final String STRING_FIXTURE = "Hello World";
- /**
- * Tests the problem reported in CODEC-130. Missing / wrong implementation of skip.
- */
- @Test
- public void testCodec130() throws IOException {
- final ByteArrayOutputStream bos = new ByteArrayOutputStream();
- try (final Base64OutputStream base64os = new Base64OutputStream(bos)) {
- base64os.write(StringUtils.getBytesUtf8(STRING_FIXTURE));
- }
-
- final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
- final Base64InputStream ins = new Base64InputStream(bis);
-
- // we skip the first character read from the reader
- ins.skip(1);
- final byte[] decodedBytes = BaseNTestData.streamToBytes(ins, new byte[64]);
- final String str = StringUtils.newStringUtf8(decodedBytes);
-
- assertEquals(STRING_FIXTURE.substring(1), str);
- }
-
- /**
- * Tests the bug reported in CODEC-105. Bad interactions with InputStream when reading one byte at a time.
- */
- @Test
- public void testCodec105() throws IOException {
- try (final Base64InputStream in = new Base64InputStream(new Codec105ErrorInputStream(), true, 0, null)) {
- for (int i = 0; i < 5; i++) {
- in.read();
- }
- }
- }
-
- /**
- * Test for the CODEC-101 bug: InputStream.read(byte[]) should never return 0 because Java's builtin InputStreamReader hates that.
- *
- * @throws Exception
- * for some failure scenarios.
- */
- @Test
- public void testCodec101() throws Exception {
- final byte[] codec101 = StringUtils.getBytesUtf8(Base64TestData.CODEC_101_INPUT_LENGTH_IS_MULTIPLE_OF_3);
- final ByteArrayInputStream bais = new ByteArrayInputStream(codec101);
- try (final Base64InputStream in = new Base64InputStream(bais)) {
- final byte[] result = new byte[8192];
- int c = in.read(result);
- assertTrue(c > 0, "Codec101: First read successful [c=" + c + "]");
-
- c = in.read(result);
- assertTrue(c < 0, "Codec101: Second read should report end-of-stream [c=" + c + "]");
- }
- }
-
- /**
- * Another test for the CODEC-101 bug: In commons-codec-1.4 this test shows InputStreamReader explicitly hating an
- * InputStream.read(byte[]) return of 0:
- *
- * java.io.IOException: Underlying input stream returned zero bytes at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:268) at
- * sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306) at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158) at
- * java.io.InputStreamReader.read(InputStreamReader.java:167) at java.io.BufferedReader.fill(BufferedReader.java:136) at
- * java.io.BufferedReader.readLine(BufferedReader.java:299) at java.io.BufferedReader.readLine(BufferedReader.java:362) at
- * org.apache.commons.codec.binary.Base64InputStreamTest.testInputStreamReader(Base64InputStreamTest.java:75)
- *
- * But in commons-codec-1.5 it's fixed. :-)
- *
- * @throws Exception
- * for some failure scenarios.
- */
- @Test
- public void testInputStreamReader() throws Exception {
- final byte[] codec101 = StringUtils.getBytesUtf8(Base64TestData.CODEC_101_INPUT_LENGTH_IS_MULTIPLE_OF_3);
- final ByteArrayInputStream bais = new ByteArrayInputStream(codec101);
- final Base64InputStream in = new Base64InputStream(bais);
- final InputStreamReader isr = new InputStreamReader(in);
- try (final BufferedReader br = new BufferedReader(isr)) {
- final String line = br.readLine();
- assertNotNull(line, "Codec101: InputStreamReader works!");
- }
- }
-
- /**
- * Test the Base64InputStream implementation against the special NPE inducing input identified in the CODEC-98 bug.
- *
- * @throws Exception
- * for some failure scenarios.
- */
- @Test
- public void testCodec98NPE() throws Exception {
- final byte[] codec98 = StringUtils.getBytesUtf8(Base64TestData.CODEC_98_NPE);
- final ByteArrayInputStream data = new ByteArrayInputStream(codec98);
- final Base64InputStream stream = new Base64InputStream(data);
-
- // This line causes an NPE in commons-codec-1.4.jar:
- final byte[] decodedBytes = BaseNTestData.streamToBytes(stream, new byte[1024]);
-
- final String decoded = StringUtils.newStringUtf8(decodedBytes);
- assertEquals(Base64TestData.CODEC_98_NPE_DECODED, decoded, "codec-98 NPE Base64InputStream");
- }
-
/**
* Tests skipping past the end of a stream.
*
@@ -169,6 +70,13 @@ public class Base64InputStreamTest {
}
}
+ private void testBase64EmptyInputStream(final int chuckSize) throws Exception {
+ final byte[] emptyEncoded = {};
+ final byte[] emptyDecoded = {};
+ testByteByByte(emptyEncoded, emptyDecoded, chuckSize, CRLF);
+ testByChunk(emptyEncoded, emptyDecoded, chuckSize, CRLF);
+ }
+
/**
* Tests the Base64InputStream implementation against empty input.
*
@@ -191,13 +99,6 @@ public class Base64InputStreamTest {
testBase64EmptyInputStream(BaseNCodec.PEM_CHUNK_SIZE);
}
- private void testBase64EmptyInputStream(final int chuckSize) throws Exception {
- final byte[] emptyEncoded = {};
- final byte[] emptyDecoded = {};
- testByteByByte(emptyEncoded, emptyDecoded, chuckSize, CRLF);
- testByChunk(emptyEncoded, emptyDecoded, chuckSize, CRLF);
- }
-
/**
* Tests the Base64InputStream implementation.
*
@@ -388,6 +289,105 @@ public class Base64InputStreamTest {
in.close();
}
+ /**
+ * Test for the CODEC-101 bug: InputStream.read(byte[]) should never return 0 because Java's builtin InputStreamReader hates that.
+ *
+ * @throws Exception
+ * for some failure scenarios.
+ */
+ @Test
+ public void testCodec101() throws Exception {
+ final byte[] codec101 = StringUtils.getBytesUtf8(Base64TestData.CODEC_101_INPUT_LENGTH_IS_MULTIPLE_OF_3);
+ final ByteArrayInputStream bais = new ByteArrayInputStream(codec101);
+ try (final Base64InputStream in = new Base64InputStream(bais)) {
+ final byte[] result = new byte[8192];
+ int c = in.read(result);
+ assertTrue(c > 0, "Codec101: First read successful [c=" + c + "]");
+
+ c = in.read(result);
+ assertTrue(c < 0, "Codec101: Second read should report end-of-stream [c=" + c + "]");
+ }
+ }
+
+ /**
+ * Tests the bug reported in CODEC-105. Bad interactions with InputStream when reading one byte at a time.
+ */
+ @Test
+ public void testCodec105() throws IOException {
+ try (final Base64InputStream in = new Base64InputStream(new Codec105ErrorInputStream(), true, 0, null)) {
+ for (int i = 0; i < 5; i++) {
+ in.read();
+ }
+ }
+ }
+
+ /**
+ * Tests the problem reported in CODEC-130. Missing / wrong implementation of skip.
+ */
+ @Test
+ public void testCodec130() throws IOException {
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ try (final Base64OutputStream base64os = new Base64OutputStream(bos)) {
+ base64os.write(StringUtils.getBytesUtf8(STRING_FIXTURE));
+ }
+
+ final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
+ final Base64InputStream ins = new Base64InputStream(bis);
+
+ // we skip the first character read from the reader
+ ins.skip(1);
+ final byte[] decodedBytes = BaseNTestData.streamToBytes(ins, new byte[64]);
+ final String str = StringUtils.newStringUtf8(decodedBytes);
+
+ assertEquals(STRING_FIXTURE.substring(1), str);
+ }
+
+ /**
+ * Test the Base64InputStream implementation against the special NPE inducing input identified in the CODEC-98 bug.
+ *
+ * @throws Exception
+ * for some failure scenarios.
+ */
+ @Test
+ public void testCodec98NPE() throws Exception {
+ final byte[] codec98 = StringUtils.getBytesUtf8(Base64TestData.CODEC_98_NPE);
+ final ByteArrayInputStream data = new ByteArrayInputStream(codec98);
+ final Base64InputStream stream = new Base64InputStream(data);
+
+ // This line causes an NPE in commons-codec-1.4.jar:
+ final byte[] decodedBytes = BaseNTestData.streamToBytes(stream, new byte[1024]);
+
+ final String decoded = StringUtils.newStringUtf8(decodedBytes);
+ assertEquals(Base64TestData.CODEC_98_NPE_DECODED, decoded, "codec-98 NPE Base64InputStream");
+ }
+
+ /**
+ * Another test for the CODEC-101 bug: In commons-codec-1.4 this test shows InputStreamReader explicitly hating an
+ * InputStream.read(byte[]) return of 0:
+ *
+ * java.io.IOException: Underlying input stream returned zero bytes at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:268) at
+ * sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306) at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158) at
+ * java.io.InputStreamReader.read(InputStreamReader.java:167) at java.io.BufferedReader.fill(BufferedReader.java:136) at
+ * java.io.BufferedReader.readLine(BufferedReader.java:299) at java.io.BufferedReader.readLine(BufferedReader.java:362) at
+ * org.apache.commons.codec.binary.Base64InputStreamTest.testInputStreamReader(Base64InputStreamTest.java:75)
+ *
+ * But in commons-codec-1.5 it's fixed. :-)
+ *
+ * @throws Exception
+ * for some failure scenarios.
+ */
+ @Test
+ public void testInputStreamReader() throws Exception {
+ final byte[] codec101 = StringUtils.getBytesUtf8(Base64TestData.CODEC_101_INPUT_LENGTH_IS_MULTIPLE_OF_3);
+ final ByteArrayInputStream bais = new ByteArrayInputStream(codec101);
+ final Base64InputStream in = new Base64InputStream(bais);
+ final InputStreamReader isr = new InputStreamReader(in);
+ try (final BufferedReader br = new BufferedReader(isr)) {
+ final String line = br.readLine();
+ assertNotNull(line, "Codec101: InputStreamReader works!");
+ }
+ }
+
/**
* Tests markSupported.
*
@@ -404,6 +404,24 @@ public class Base64InputStreamTest {
}
}
+ /**
+ * Tests read returning 0
+ *
+ * @throws Exception
+ * for some failure scenarios.
+ */
+ @Test
+ public void testRead0() throws Exception {
+ final byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE);
+ final byte[] buf = new byte[1024];
+ int bytesRead = 0;
+ final ByteArrayInputStream bin = new ByteArrayInputStream(decoded);
+ try (final Base64InputStream in = new Base64InputStream(bin, true, 4, new byte[] { 0, 0, 0 })) {
+ bytesRead = in.read(buf, 0, 0);
+ assertEquals(0, bytesRead, "Base64InputStream.read(buf, 0, 0) returns 0");
+ }
+ }
+
/**
* Tests read using different buffer sizes
*
@@ -428,24 +446,6 @@ public class Base64InputStreamTest {
assertArrayEquals(decoded, out.toByteArray());
}
- /**
- * Tests read returning 0
- *
- * @throws Exception
- * for some failure scenarios.
- */
- @Test
- public void testRead0() throws Exception {
- final byte[] decoded = StringUtils.getBytesUtf8(STRING_FIXTURE);
- final byte[] buf = new byte[1024];
- int bytesRead = 0;
- final ByteArrayInputStream bin = new ByteArrayInputStream(decoded);
- try (final Base64InputStream in = new Base64InputStream(bin, true, 4, new byte[] { 0, 0, 0 })) {
- bytesRead = in.read(buf, 0, 0);
- assertEquals(0, bytesRead, "Base64InputStream.read(buf, 0, 0) returns 0");
- }
- }
-
/**
* Tests read with null.
*
diff --git a/src/test/java/org/apache/commons/codec/binary/Base64OutputStreamTest.java b/src/test/java/org/apache/commons/codec/binary/Base64OutputStreamTest.java
index 4c1d229f..0758bb6d 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base64OutputStreamTest.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base64OutputStreamTest.java
@@ -40,25 +40,11 @@ public class Base64OutputStreamTest {
private static final String STRING_FIXTURE = "Hello World";
- /**
- * Test the Base64OutputStream implementation against the special NPE inducing input
- * identified in the CODEC-98 bug.
- *
- * @throws Exception for some failure scenarios.
- */
- @Test
- public void testCodec98NPE() throws Exception {
- final byte[] codec98 = StringUtils.getBytesUtf8(Base64TestData.CODEC_98_NPE);
- final byte[] codec98_1024 = new byte[1024];
- System.arraycopy(codec98, 0, codec98_1024, 0, codec98.length);
- final ByteArrayOutputStream data = new ByteArrayOutputStream(1024);
- try (final Base64OutputStream stream = new Base64OutputStream(data, false)) {
- stream.write(codec98_1024, 0, 1024);
- }
-
- final byte[] decodedBytes = data.toByteArray();
- final String decoded = StringUtils.newStringUtf8(decodedBytes);
- assertEquals(Base64TestData.CODEC_98_NPE_DECODED, decoded, "codec-98 NPE Base64OutputStream");
+ private void testBase64EmptyOutputStream(final int chunkSize) throws Exception {
+ final byte[] emptyEncoded = {};
+ final byte[] emptyDecoded = {};
+ testByteByByte(emptyEncoded, emptyDecoded, chunkSize, CR_LF);
+ testByChunk(emptyEncoded, emptyDecoded, chunkSize, CR_LF);
}
@@ -84,13 +70,6 @@ public class Base64OutputStreamTest {
testBase64EmptyOutputStream(BaseNCodec.PEM_CHUNK_SIZE);
}
- private void testBase64EmptyOutputStream(final int chunkSize) throws Exception {
- final byte[] emptyEncoded = {};
- final byte[] emptyDecoded = {};
- testByteByByte(emptyEncoded, emptyDecoded, chunkSize, CR_LF);
- testByChunk(emptyEncoded, emptyDecoded, chunkSize, CR_LF);
- }
-
/**
* Test the Base64OutputStream implementation
*
@@ -287,35 +266,24 @@ public class Base64OutputStreamTest {
}
/**
- * Tests Base64OutputStream.write for expected IndexOutOfBoundsException conditions.
+ * Test the Base64OutputStream implementation against the special NPE inducing input
+ * identified in the CODEC-98 bug.
*
- * @throws Exception
- * for some failure scenarios.
+ * @throws Exception for some failure scenarios.
*/
@Test
- public void testWriteOutOfBounds() throws Exception {
- final byte[] buf = new byte[1024];
- final ByteArrayOutputStream bout = new ByteArrayOutputStream();
- try (final Base64OutputStream out = new Base64OutputStream(bout)) {
- assertThrows(IndexOutOfBoundsException.class, () -> out.write(buf, -1, 1), "Base64OutputStream.write(buf, -1, 1)");
- assertThrows(IndexOutOfBoundsException.class, () -> out.write(buf, 1, -1), "Base64OutputStream.write(buf, 1, -1)");
- assertThrows(IndexOutOfBoundsException.class, () -> out.write(buf, buf.length + 1, 0), "Base64OutputStream.write(buf, buf.length + 1, 0)");
- assertThrows(IndexOutOfBoundsException.class, () -> out.write(buf, buf.length - 1, 2), "Base64OutputStream.write(buf, buf.length - 1, 2)");
+ public void testCodec98NPE() throws Exception {
+ final byte[] codec98 = StringUtils.getBytesUtf8(Base64TestData.CODEC_98_NPE);
+ final byte[] codec98_1024 = new byte[1024];
+ System.arraycopy(codec98, 0, codec98_1024, 0, codec98.length);
+ final ByteArrayOutputStream data = new ByteArrayOutputStream(1024);
+ try (final Base64OutputStream stream = new Base64OutputStream(data, false)) {
+ stream.write(codec98_1024, 0, 1024);
}
- }
- /**
- * Tests Base64OutputStream.write(null).
- *
- * @throws Exception
- * for some failure scenarios.
- */
- @Test
- public void testWriteToNullCoverage() throws Exception {
- final ByteArrayOutputStream bout = new ByteArrayOutputStream();
- try (final Base64OutputStream out = new Base64OutputStream(bout)) {
- assertThrows(NullPointerException.class, () -> out.write(null, 0, 0));
- }
+ final byte[] decodedBytes = data.toByteArray();
+ final String decoded = StringUtils.newStringUtf8(decodedBytes);
+ assertEquals(Base64TestData.CODEC_98_NPE_DECODED, decoded, "codec-98 NPE Base64OutputStream");
}
/**
@@ -347,4 +315,36 @@ public class Base64OutputStreamTest {
});
}
}
+
+ /**
+ * Tests Base64OutputStream.write for expected IndexOutOfBoundsException conditions.
+ *
+ * @throws Exception
+ * for some failure scenarios.
+ */
+ @Test
+ public void testWriteOutOfBounds() throws Exception {
+ final byte[] buf = new byte[1024];
+ final ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ try (final Base64OutputStream out = new Base64OutputStream(bout)) {
+ assertThrows(IndexOutOfBoundsException.class, () -> out.write(buf, -1, 1), "Base64OutputStream.write(buf, -1, 1)");
+ assertThrows(IndexOutOfBoundsException.class, () -> out.write(buf, 1, -1), "Base64OutputStream.write(buf, 1, -1)");
+ assertThrows(IndexOutOfBoundsException.class, () -> out.write(buf, buf.length + 1, 0), "Base64OutputStream.write(buf, buf.length + 1, 0)");
+ assertThrows(IndexOutOfBoundsException.class, () -> out.write(buf, buf.length - 1, 2), "Base64OutputStream.write(buf, buf.length - 1, 2)");
+ }
+ }
+
+ /**
+ * Tests Base64OutputStream.write(null).
+ *
+ * @throws Exception
+ * for some failure scenarios.
+ */
+ @Test
+ public void testWriteToNullCoverage() throws Exception {
+ final ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ try (final Base64OutputStream out = new Base64OutputStream(bout)) {
+ assertThrows(NullPointerException.class, () -> out.write(null, 0, 0));
+ }
+ }
}
diff --git a/src/test/java/org/apache/commons/codec/binary/Base64Test.java b/src/test/java/org/apache/commons/codec/binary/Base64Test.java
index 151bfef1..5855911f 100644
--- a/src/test/java/org/apache/commons/codec/binary/Base64Test.java
+++ b/src/test/java/org/apache/commons/codec/binary/Base64Test.java
@@ -72,6 +72,60 @@ public class Base64Test {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};
+ /**
+ * Test base 64 decoding of the final trailing bits. Trailing encoded bytes
+ * cannot fit exactly into 6-bit characters so the last character has a limited
+ * alphabet where the final bits are zero. This asserts that illegal final
+ * characters throw an exception when decoding.
+ *
+ * @param nbits the number of trailing bits (must be a factor of 6 and {@code <24})
+ */
+ private static void assertBase64DecodingOfTrailingBits(final int nbits) {
+ final Base64 codec = new Base64(0, null, false, CodecPolicy.STRICT);
+ // Requires strict decoding
+ assertTrue(codec.isStrictDecoding());
+ assertEquals(CodecPolicy.STRICT, codec.getCodecPolicy());
+ // A lenient decoder should not re-encode to the same bytes
+ final Base64 defaultCodec = new Base64();
+ assertFalse(defaultCodec.isStrictDecoding());
+ assertEquals(CodecPolicy.LENIENT, defaultCodec.getCodecPolicy());
+
+ // Create the encoded bytes. The first characters must be valid so fill with 'zero'
+ // then pad to the block size.
+ final int length = nbits / 6;
+ final byte[] encoded = new byte[4];
+ Arrays.fill(encoded, 0, length, STANDARD_ENCODE_TABLE[0]);
+ Arrays.fill(encoded, length, encoded.length, (byte) '=');
+ // Compute how many bits would be discarded from 8-bit bytes
+ final int discard = nbits % 8;
+ final int emptyBitsMask = (1 << discard) - 1;
+ // Special case when an impossible number of trailing characters
+ final boolean invalid = length == 1;
+ // Enumerate all 64 possible final characters in the last position
+ final int last = length - 1;
+ for (int i = 0; i < 64; i++) {
+ encoded[last] = STANDARD_ENCODE_TABLE[i];
+ // If the lower bits are set we expect an exception. This is not a valid
+ // final character.
+ if (invalid || (i & emptyBitsMask) != 0) {
+ assertThrows(IllegalArgumentException.class, () -> codec.decode(encoded),
+ "Final base-64 digit should not be allowed");
+ // The default lenient mode should decode this
+ final byte[] decoded = defaultCodec.decode(encoded);
+ // Re-encoding should not match the original array as it was invalid
+ assertFalse(Arrays.equals(encoded, defaultCodec.encode(decoded)));
+ } else {
+ // Otherwise this should decode
+ final byte[] decoded = codec.decode(encoded);
+ // Compute the bits that were encoded. This should match the final decoded byte.
+ final int bitsEncoded = i >> discard;
+ assertEquals(bitsEncoded, decoded[decoded.length - 1], "Invalid decoding of last character");
+ // Re-encoding should match the original array (requires the same padding character)
+ assertArrayEquals(encoded, codec.encode(decoded));
+ }
+ }
+ }
+
private final Random random = new Random();
/**
@@ -81,24 +135,6 @@ public class Base64Test {
return this.random;
}
- /**
- * Test the isStringBase64 method.
- */
- @Test
- public void testIsStringBase64() {
- final String nullString = null;
- final String emptyString = "";
- final String validString = "abc===defg\n\r123456\r789\r\rABC\n\nDEF==GHI\r\nJKL==============";
- final String invalidString = validString + (char) 0; // append null character
-
- assertThrows(NullPointerException.class, () -> Base64.isBase64(nullString),
- "Base64.isStringBase64() should not be null-safe.");
-
- assertTrue(Base64.isBase64(emptyString), "Base64.isStringBase64(empty-string) is true");
- assertTrue(Base64.isBase64(validString), "Base64.isStringBase64(valid-string) is true");
- assertFalse(Base64.isBase64(invalidString), "Base64.isStringBase64(invalid-string) is false");
- }
-
/**
* Test the Base64 implementation
*/
@@ -131,19 +167,42 @@ public class Base64Test {
assertEquals("Hello World", decodeString, "decode hello world");
}
+ @Test
+ public void testBase64AtBufferEnd() {
+ testBase64InBuffer(100, 0);
+ }
+
+ @Test
+ public void testBase64AtBufferMiddle() {
+ testBase64InBuffer(100, 100);
+ }
+
@Test
public void testBase64AtBufferStart() {
testBase64InBuffer(0, 100);
}
@Test
- public void testBase64AtBufferEnd() {
- testBase64InBuffer(100, 0);
+ public void testBase64DecodingOfTrailing12Bits() {
+ assertBase64DecodingOfTrailingBits(12);
}
@Test
- public void testBase64AtBufferMiddle() {
- testBase64InBuffer(100, 100);
+ public void testBase64DecodingOfTrailing18Bits() {
+ assertBase64DecodingOfTrailingBits(18);
+ }
+
+ @Test
+ public void testBase64DecodingOfTrailing6Bits() {
+ assertBase64DecodingOfTrailingBits(6);
+ }
+
+ @Test
+ public void testBase64ImpossibleSamples() {
+ final Base64 codec = new Base64(0, null, false, CodecPolicy.STRICT);
+ for (final String s : BASE64_IMPOSSIBLE_CASES) {
+ assertThrows(IllegalArgumentException.class, () -> codec.decode(s));
+ }
}
private void testBase64InBuffer(final int startPasSize, final int endPadSize) {
@@ -157,25 +216,34 @@ public class Base64Test {
assertEquals("SGVsbG8gV29ybGQ=", encodedContent, "encoding hello world");
}
- /**
- * Test our decode with pad character in the middle. (Our current
- * implementation: halt decode and return what we've got so far).
- *
- * The point of this test is not to say
- * "this is the correct way to decode base64." The point is simply to keep
- * us aware of the current logic since 1.4 so we don't accidentally break it
- * without realizing.
- *
- * Note for historians. The 1.3 logic would decode to:
- * "Hello World\u0000Hello World" -- null in the middle --- and 1.4
- * unwittingly changed it to current logic.
- */
@Test
- public void testDecodeWithInnerPad() {
- final String content = "SGVsbG8gV29ybGQ=SGVsbG8gV29ybGQ=";
- final byte[] result = Base64.decodeBase64(content);
- final byte[] shouldBe = StringUtils.getBytesUtf8("Hello World");
- assertArrayEquals(result, shouldBe, "decode should halt at pad (=)");
+ public void testByteToStringVariations() throws DecoderException {
+ final Base64 base64 = new Base64(0);
+ final byte[] b1 = StringUtils.getBytesUtf8("Hello World");
+ final byte[] b2 = {};
+ final byte[] b3 = null;
+ final byte[] b4 = Hex.decodeHex("2bf7cc2701fe4397b49ebeed5acc7090"); // for
+ // url-safe
+ // tests
+
+ assertEquals("SGVsbG8gV29ybGQ=", base64.encodeToString(b1),
+ "byteToString Hello World");
+ assertEquals( "SGVsbG8gV29ybGQ=", Base64.encodeBase64String(b1),
+ "byteToString static Hello World");
+ assertEquals("", base64.encodeToString(b2),
+ "byteToString \"\"");
+ assertEquals("", Base64.encodeBase64String(b2),
+ "byteToString static \"\"");
+ assertNull(base64.encodeToString(b3),
+ "byteToString null");
+ assertNull(Base64.encodeBase64String(b3),
+ "byteToString static null");
+ assertEquals("K/fMJwH+Q5e0nr7tWsxwkA==", base64.encodeToString(b4),
+ "byteToString UUID");
+ assertEquals("K/fMJwH+Q5e0nr7tWsxwkA==", Base64.encodeBase64String(b4),
+ "byteToString static UUID");
+ assertEquals("K_fMJwH-Q5e0nr7tWsxwkA", Base64.encodeBase64URLSafeString(b4),
+ "byteToString static-url-safe UUID");
}
/**
@@ -192,6 +260,49 @@ public class Base64Test {
assertArrayEquals(expectedEncode, actualEncode, "chunkedEncodeMultipleOf76");
}
+ @Test
+ public void testCodec112() { // size calculation assumes always chunked
+ final byte[] in = { 0 };
+ final byte[] out = Base64.encodeBase64(in);
+ Base64.encodeBase64(in, false, false, out.length);
+ // TODO Assert??
+ }
+
+ /**
+ * 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
+ public void testCodec265() {
+ // 1GiB file to encode: 2^30 bytes
+ final int size1GiB = 1 << 30;
+
+ // Expecting a size of 4 output bytes per 3 input bytes plus the trailing bytes
+ // padded to a block size of 4.
+ final int blocks = (int) Math.ceil(size1GiB / 3.0);
+ final int expectedLength = 4 * blocks;
+
+ // This test is memory hungry. Check we can run it.
+ final long presumableFreeMemory = BaseNCodecTest.getPresumableFreeMemory();
+
+ // Estimate the maximum memory required:
+ // 1GiB + 1GiB + ~2GiB + ~1.33GiB + 32 KiB = ~5.33GiB
+ //
+ // 1GiB: Input buffer to encode
+ // 1GiB: Existing working buffer (due to doubling of default buffer size of 8192)
+ // ~2GiB: New working buffer to allocate (due to doubling)
+ // ~1.33GiB: Expected output size (since the working buffer is copied at the end)
+ // 32KiB: Some headroom
+ final long estimatedMemory = (long) size1GiB * 4 + expectedLength + 32 * 1024;
+ Assumptions.assumeTrue(presumableFreeMemory > estimatedMemory,
+ "Not enough free memory for the test");
+
+ final byte[] bytes = new byte[size1GiB];
+ final byte[] encoded = Base64.encodeBase64(bytes);
+ assertEquals(expectedLength, encoded.length);
+ }
+
/**
* CODEC-68: isBase64 throws ArrayIndexOutOfBoundsException on some
* non-BASE64 bytes
@@ -261,6 +372,31 @@ public class Base64Test {
"Exception not thrown when passing in null to encodeInteger(BigInteger)");
}
+ @Test
+ public void testConstructor_Int_ByteArray_Boolean() {
+ final Base64 base64 = new Base64(65, new byte[] { '\t' }, false);
+ final byte[] encoded = base64.encode(BaseNTestData.DECODED);
+ String expectedResult = Base64TestData.ENCODED_64_CHARS_PER_LINE;
+ expectedResult = expectedResult.replace('\n', '\t');
+ final String result = StringUtils.newStringUtf8(encoded);
+ assertEquals(expectedResult, result, "new Base64(65, \\t, false)");
+ }
+
+ @Test
+ public void testConstructor_Int_ByteArray_Boolean_UrlSafe() {
+ // url-safe variation
+ final Base64 base64 = new Base64(64, new byte[] { '\t' }, true);
+ final byte[] encoded = base64.encode(BaseNTestData.DECODED);
+ String expectedResult = Base64TestData.ENCODED_64_CHARS_PER_LINE;
+ expectedResult = expectedResult.replace("=", ""); // url-safe has no
+ // == padding.
+ expectedResult = expectedResult.replace('\n', '\t');
+ expectedResult = expectedResult.replace('+', '-');
+ expectedResult = expectedResult.replace('/', '_');
+ final String result = StringUtils.newStringUtf8(encoded);
+ assertEquals(result, expectedResult, "new Base64(64, \\t, true)");
+ }
+
@Test
public void testConstructors() {
Base64 base64;
@@ -290,29 +426,10 @@ public class Base64Test {
assertNotNull(base64);
}
- @Test
- public void testConstructor_Int_ByteArray_Boolean() {
- final Base64 base64 = new Base64(65, new byte[] { '\t' }, false);
- final byte[] encoded = base64.encode(BaseNTestData.DECODED);
- String expectedResult = Base64TestData.ENCODED_64_CHARS_PER_LINE;
- expectedResult = expectedResult.replace('\n', '\t');
- final String result = StringUtils.newStringUtf8(encoded);
- assertEquals(expectedResult, result, "new Base64(65, \\t, false)");
- }
-
- @Test
- public void testConstructor_Int_ByteArray_Boolean_UrlSafe() {
- // url-safe variation
- final Base64 base64 = new Base64(64, new byte[] { '\t' }, true);
- final byte[] encoded = base64.encode(BaseNTestData.DECODED);
- String expectedResult = Base64TestData.ENCODED_64_CHARS_PER_LINE;
- expectedResult = expectedResult.replace("=", ""); // url-safe has no
- // == padding.
- expectedResult = expectedResult.replace('\n', '\t');
- expectedResult = expectedResult.replace('+', '-');
- expectedResult = expectedResult.replace('/', '_');
- final String result = StringUtils.newStringUtf8(encoded);
- assertEquals(result, expectedResult, "new Base64(64, \\t, true)");
+ private void testDecodeEncode(final String encodedText) {
+ final String decodedText = StringUtils.newStringUsAscii(Base64.decodeBase64(encodedText));
+ final String encodedText2 = Base64.encodeBase64String(StringUtils.getBytesUtf8(decodedText));
+ assertEquals(encodedText, encodedText2);
}
/**
@@ -354,6 +471,27 @@ public class Base64Test {
assertEquals(0, Base64.decodeBase64("\n".getBytes(CHARSET_UTF8)).length);
}
+ /**
+ * Test our decode with pad character in the middle. (Our current
+ * implementation: halt decode and return what we've got so far).
+ *
+ * The point of this test is not to say
+ * "this is the correct way to decode base64." The point is simply to keep
+ * us aware of the current logic since 1.4 so we don't accidentally break it
+ * without realizing.
+ *
+ * Note for historians. The 1.3 logic would decode to:
+ * "Hello World\u0000Hello World" -- null in the middle --- and 1.4
+ * unwittingly changed it to current logic.
+ */
+ @Test
+ public void testDecodeWithInnerPad() {
+ final String content = "SGVsbG8gV29ybGQ=SGVsbG8gV29ybGQ=";
+ final byte[] result = Base64.decodeBase64(content);
+ final byte[] shouldBe = StringUtils.getBytesUtf8("Hello World");
+ assertArrayEquals(result, shouldBe, "decode should halt at pad (=)");
+ }
+
@Test
public void testDecodeWithWhitespace() throws Exception {
@@ -394,6 +532,12 @@ public class Base64Test {
assertNull(Base64.decodeBase64((byte[]) null), "empty base64 encode");
}
+ private void testEncodeDecode(final String plainText) {
+ final String encodedText = Base64.encodeBase64String(StringUtils.getBytesUtf8(plainText));
+ final String decodedText = StringUtils.newStringUsAscii(Base64.decodeBase64(encodedText));
+ assertEquals(plainText, decodedText);
+ }
+
// encode/decode a large random array
@Test
public void testEncodeDecodeRandom() {
@@ -428,18 +572,26 @@ public class Base64Test {
testEncodeOverMaxSize(2);
}
- @Test
- public void testCodec112() { // size calculation assumes always chunked
- final byte[] in = { 0 };
- final byte[] out = Base64.encodeBase64(in);
- Base64.encodeBase64(in, false, false, out.length);
- // TODO Assert??
- }
-
private void testEncodeOverMaxSize(final int maxSize) {
assertThrows(IllegalArgumentException.class, () -> Base64.encodeBase64(BaseNTestData.DECODED, true, false, maxSize));
}
+ /**
+ * Tests a lineSeparator much bigger than DEFAULT_BUFFER_SIZE.
+ *
+ * @see "<a href='https://mail-archives.apache.org/mod_mbox/commons-dev/201202.mbox/%3C4F3C85D7.5060706@snafu.de%3E'>dev@commons.apache.org</a>"
+ */
+ @Test
+ public void testHugeLineSeparator() {
+ final int BaseNCodec_DEFAULT_BUFFER_SIZE = 8192;
+ final int Base64_BYTES_PER_ENCODED_BLOCK = 4;
+ final byte[] baLineSeparator = new byte[BaseNCodec_DEFAULT_BUFFER_SIZE * 4 - 3];
+ final Base64 b64 = new Base64(Base64_BYTES_PER_ENCODED_BLOCK, baLineSeparator);
+ final String strOriginal = "Hello World";
+ final String strDecoded = new String(b64.decode(b64.encode(StringUtils.getBytesUtf8(strOriginal))));
+ assertEquals(strOriginal, strDecoded, "testDEFAULT_BUFFER_SIZE");
+ }
+
@Test
public void testIgnoringNonBase64InDecode() throws Exception {
assertEquals("The quick brown fox jumped over the lazy dogs.",
@@ -467,6 +619,24 @@ public class Base64Test {
assertFalse(Base64.isBase64(new byte[] { '$' }));
}
+ /**
+ * Test the isStringBase64 method.
+ */
+ @Test
+ public void testIsStringBase64() {
+ final String nullString = null;
+ final String emptyString = "";
+ final String validString = "abc===defg\n\r123456\r789\r\rABC\n\nDEF==GHI\r\nJKL==============";
+ final String invalidString = validString + (char) 0; // append null character
+
+ assertThrows(NullPointerException.class, () -> Base64.isBase64(nullString),
+ "Base64.isStringBase64() should not be null-safe.");
+
+ assertTrue(Base64.isBase64(emptyString), "Base64.isStringBase64(empty-string) is true");
+ assertTrue(Base64.isBase64(validString), "Base64.isStringBase64(valid-string) is true");
+ assertFalse(Base64.isBase64(invalidString), "Base64.isStringBase64(invalid-string) is false");
+ }
+
/**
* Tests isUrlSafe.
*/
@@ -558,6 +728,12 @@ public class Base64Test {
assertEquals(original, dest, "dest string does not equal original");
}
+ @Test
+ public void testObjectEncode() throws Exception {
+ final Base64 b64 = new Base64();
+ assertEquals("SGVsbG8gV29ybGQ=", new String(b64.encode("Hello World".getBytes(CHARSET_UTF8))));
+ }
+
@Test
public void testObjectEncodeWithInvalidParameter() {
assertThrows(EncoderException.class, () -> new Base64().encode("Yadayadayada"),
@@ -578,12 +754,6 @@ public class Base64Test {
assertEquals(original, dest, "dest string does not equal original");
}
- @Test
- public void testObjectEncode() throws Exception {
- final Base64 b64 = new Base64();
- assertEquals("SGVsbG8gV29ybGQ=", new String(b64.encode("Hello World".getBytes(CHARSET_UTF8))));
- }
-
@Test
public void testPairs() {
assertEquals("AAA=", new String(Base64.encodeBase64(new byte[] { 0, 0 })));
@@ -593,6 +763,14 @@ public class Base64Test {
}
}
+ /**
+ * Tests RFC 1421 section 4.3.2.4 chuck size definition.
+ */
+ @Test
+ public void testRfc1421Section6Dot8ChunkSizeDefinition() {
+ assertEquals(64, BaseNCodec.PEM_CHUNK_SIZE);
+ }
+
/**
* Tests RFC 2045 section 2.1 CRLF definition.
*/
@@ -609,14 +787,6 @@ public class Base64Test {
assertEquals(76, BaseNCodec.MIME_CHUNK_SIZE);
}
- /**
- * Tests RFC 1421 section 4.3.2.4 chuck size definition.
- */
- @Test
- public void testRfc1421Section6Dot8ChunkSizeDefinition() {
- assertEquals(64, BaseNCodec.PEM_CHUNK_SIZE);
- }
-
/**
* Tests RFC 4648 section 10 test vectors.
* <ul>
@@ -643,6 +813,32 @@ public class Base64Test {
assertEquals("foobar", StringUtils.newStringUsAscii(Base64.decodeBase64("Zm9vYmFy")));
}
+ /**
+ * Tests RFC 4648 section 10 test vectors.
+ * <ul>
+ * <li>BASE64("") = ""</li>
+ * <li>BASE64("f") = "Zg=="</li>
+ * <li>BASE64("fo") = "Zm8="</li>
+ * <li>BASE64("foo") = "Zm9v"</li>
+ * <li>BASE64("foob") = "Zm9vYg=="</li>
+ * <li>BASE64("fooba") = "Zm9vYmE="</li>
+ * <li>BASE64("foobar") = "Zm9vYmFy"</li>
+ * </ul>
+ *
+ * @see <a href="http://tools.ietf.org/html/rfc4648">http://tools.ietf.org/
+ * html/rfc4648</a>
+ */
+ @Test
+ public void testRfc4648Section10DecodeEncode() {
+ testDecodeEncode("");
+ testDecodeEncode("Zg==");
+ testDecodeEncode("Zm8=");
+ testDecodeEncode("Zm9v");
+ testDecodeEncode("Zm9vYg==");
+ testDecodeEncode("Zm9vYmE=");
+ testDecodeEncode("Zm9vYmFy");
+ }
+
/**
* Tests RFC 4648 section 10 test vectors.
* <ul>
@@ -696,38 +892,6 @@ public class Base64Test {
assertEquals("Zm9vYmFy", Base64.encodeBase64String(StringUtils.getBytesUtf8("foobar")));
}
- /**
- * Tests RFC 4648 section 10 test vectors.
- * <ul>
- * <li>BASE64("") = ""</li>
- * <li>BASE64("f") = "Zg=="</li>
- * <li>BASE64("fo") = "Zm8="</li>
- * <li>BASE64("foo") = "Zm9v"</li>
- * <li>BASE64("foob") = "Zm9vYg=="</li>
- * <li>BASE64("fooba") = "Zm9vYmE="</li>
- * <li>BASE64("foobar") = "Zm9vYmFy"</li>
- * </ul>
- *
- * @see <a href="http://tools.ietf.org/html/rfc4648">http://tools.ietf.org/
- * html/rfc4648</a>
- */
- @Test
- public void testRfc4648Section10DecodeEncode() {
- testDecodeEncode("");
- testDecodeEncode("Zg==");
- testDecodeEncode("Zm8=");
- testDecodeEncode("Zm9v");
- testDecodeEncode("Zm9vYg==");
- testDecodeEncode("Zm9vYmE=");
- testDecodeEncode("Zm9vYmFy");
- }
-
- private void testDecodeEncode(final String encodedText) {
- final String decodedText = StringUtils.newStringUsAscii(Base64.decodeBase64(encodedText));
- final String encodedText2 = Base64.encodeBase64String(StringUtils.getBytesUtf8(decodedText));
- assertEquals(encodedText, encodedText2);
- }
-
/**
* Tests RFC 4648 section 10 test vectors.
* <ul>
@@ -754,12 +918,6 @@ public class Base64Test {
testEncodeDecode("foobar");
}
- private void testEncodeDecode(final String plainText) {
- final String encodedText = Base64.encodeBase64String(StringUtils.getBytesUtf8(plainText));
- final String decodedText = StringUtils.newStringUsAscii(Base64.decodeBase64(encodedText));
- assertEquals(plainText, decodedText);
- }
-
@Test
public void testSingletons() {
assertEquals("AA==", new String(Base64.encodeBase64(new byte[] { (byte) 0 })));
@@ -982,6 +1140,30 @@ public class Base64Test {
assertEquals("aA==\r\n", new String(Base64.encodeBase64Chunked(new byte[] { (byte) 104 })));
}
+ @Test
+ public void testStringToByteVariations() throws DecoderException {
+ final Base64 base64 = new Base64();
+ final String s1 = "SGVsbG8gV29ybGQ=\r\n";
+ final String s2 = "";
+ final String s3 = null;
+ final String s4a = "K/fMJwH+Q5e0nr7tWsxwkA==\r\n";
+ final String s4b = "K_fMJwH-Q5e0nr7tWsxwkA";
+ final byte[] b4 = Hex.decodeHex("2bf7cc2701fe4397b49ebeed5acc7090"); // for
+ // url-safe
+ // tests
+
+ assertEquals("Hello World", StringUtils.newStringUtf8(base64.decode(s1)), "StringToByte Hello World");
+ assertEquals("Hello World", StringUtils.newStringUtf8((byte[]) base64.decode((Object) s1)), "StringToByte Hello World");
+ assertEquals("Hello World", StringUtils.newStringUtf8(Base64.decodeBase64(s1)), "StringToByte static Hello World");
+ assertEquals("", StringUtils.newStringUtf8(base64.decode(s2)), "StringToByte \"\"");
... 7498 lines suppressed ...