Skip to content

Commit 937df54

Browse files
committed
Internal refactoring
Add missing test
1 parent ef72cbd commit 937df54

File tree

5 files changed

+76
-86
lines changed

5 files changed

+76
-86
lines changed

src/main/java/org/apache/commons/codec/binary/Base32.java

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -345,20 +345,16 @@ private Base32(final Builder builder) {
345345
super(builder);
346346
Objects.requireNonNull(builder.getEncodeTable(), "encodeTable");
347347
this.encodeTable = builder.getEncodeTable();
348-
this.decodeTable = builder.getEncodeTable() == HEX_ENCODE_TABLE || Arrays.equals(builder.getEncodeTable(), HEX_ENCODE_TABLE) ?
349-
HEX_DECODE_TABLE : DECODE_TABLE;
348+
this.decodeTable = Arrays.equals(builder.getEncodeTable(), HEX_ENCODE_TABLE) ? HEX_DECODE_TABLE : DECODE_TABLE;
350349
if (builder.getLineLength() > 0) {
351-
if (builder.getLineSeparator() == null) {
352-
throw new IllegalArgumentException("lineLength " + lineLength + " > 0, but lineSeparator is null");
353-
}
354-
final byte[] lineSeparatorCopy = builder.getLineSeparator().clone();
350+
final byte[] lineSeparator = builder.getLineSeparator();
355351
// Must be done after initializing the tables
356-
if (containsAlphabetOrPad(lineSeparatorCopy)) {
357-
final String sep = StringUtils.newStringUtf8(lineSeparatorCopy);
352+
if (containsAlphabetOrPad(lineSeparator)) {
353+
final String sep = StringUtils.newStringUtf8(lineSeparator);
358354
throw new IllegalArgumentException("lineSeparator must not contain Base32 characters: [" + sep + "]");
359355
}
360-
this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparatorCopy.length;
361-
this.lineSeparator = lineSeparatorCopy;
356+
this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparator.length;
357+
this.lineSeparator = lineSeparator;
362358
} else {
363359
this.encodeSize = BYTES_PER_ENCODED_BLOCK;
364360
this.lineSeparator = null;
@@ -499,8 +495,8 @@ public Base32(final int lineLength, final byte[] lineSeparator, final boolean us
499495
*/
500496
@Deprecated
501497
public Base32(final int lineLength, final byte[] lineSeparator, final boolean useHex, final byte padding, final CodecPolicy decodingPolicy) {
502-
this(builder().setLineLength(lineLength).setLineSeparator(lineSeparator).setEncodeTableRaw(encodeTable(useHex)).setPadding(padding)
503-
.setDecodingPolicy(decodingPolicy));
498+
this(builder().setLineLength(lineLength).setLineSeparator(lineSeparator != null ? lineSeparator : EMPTY_BYTE_ARRAY)
499+
.setEncodeTableRaw(encodeTable(useHex)).setPadding(padding).setDecodingPolicy(decodingPolicy));
504500
}
505501

506502
/**

src/main/java/org/apache/commons/codec/binary/Base64.java

Lines changed: 27 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,13 @@ public static class Builder extends AbstractBuilder<Base64, Builder> {
9898
*/
9999
public Builder() {
100100
super(STANDARD_ENCODE_TABLE);
101+
setEncodedBlockSize(BYTES_PER_ENCODED_BLOCK);
102+
setUnencodedBlockSize(BYTES_PER_UNENCODED_BLOCK);
101103
}
102104

103105
@Override
104106
public Base64 get() {
105-
return new Base64(getLineLength(), getLineSeparator(), getPadding(), getEncodeTable(), getDecodingPolicy());
107+
return new Base64(this);
106108
}
107109

108110
/**
@@ -529,6 +531,9 @@ static byte[] toUrlSafeEncodeTable(final boolean urlSafe) {
529531

530532
private final boolean isUrlSafe;
531533

534+
private final boolean isStandardEncodeTable;
535+
536+
532537
/**
533538
* Constructs a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
534539
* <p>
@@ -646,7 +651,8 @@ public Base64(final int lineLength, final byte[] lineSeparator) {
646651
*/
647652
@Deprecated
648653
public Base64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe) {
649-
this(lineLength, lineSeparator, PAD_DEFAULT, toUrlSafeEncodeTable(urlSafe), DECODING_POLICY_DEFAULT);
654+
this(builder().setLineLength(lineLength).setLineSeparator(lineSeparator != null ? lineSeparator : EMPTY_BYTE_ARRAY).setPadding(PAD_DEFAULT)
655+
.setEncodeTableRaw(toUrlSafeEncodeTable(urlSafe)).setDecodingPolicy(DECODING_POLICY_DEFAULT));
650656
}
651657

652658
/**
@@ -680,56 +686,31 @@ public Base64(final int lineLength, final byte[] lineSeparator, final boolean ur
680686
*/
681687
@Deprecated
682688
public Base64(final int lineLength, final byte[] lineSeparator, final boolean urlSafe, final CodecPolicy decodingPolicy) {
683-
this(lineLength, lineSeparator, PAD_DEFAULT, toUrlSafeEncodeTable(urlSafe), decodingPolicy);
689+
this(builder().setLineLength(lineLength).setLineSeparator(lineSeparator).setPadding(PAD_DEFAULT).setEncodeTableRaw(toUrlSafeEncodeTable(urlSafe))
690+
.setDecodingPolicy(decodingPolicy));
684691
}
685692

686-
/**
687-
* Constructs a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
688-
* <p>
689-
* When encoding the line length and line separator are given in the constructor, and the encoding table is STANDARD_ENCODE_TABLE.
690-
* </p>
691-
* <p>
692-
* Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
693-
* </p>
694-
* <p>
695-
* When decoding all variants are supported.
696-
* </p>
697-
*
698-
* @param lineLength Each line of encoded data will be at most of the given length (rounded down to the nearest multiple of 4). If lineLength &lt;= 0,
699-
* then the output will not be divided into lines (chunks). Ignored when decoding.
700-
* @param lineSeparator Each line of encoded data will end with this sequence of bytes; the constructor makes a defensive copy. May be null.
701-
* @param padding padding byte.
702-
* @param encodeTable The manual encodeTable - a byte array of 64 chars.
703-
* @param decodingPolicy The decoding policy.
704-
* @throws IllegalArgumentException Thrown when the {@code lineSeparator} contains Base64 characters.
705-
*/
706-
private Base64(final int lineLength, final byte[] lineSeparator, final byte padding, final byte[] encodeTable, final CodecPolicy decodingPolicy) {
707-
super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, lineLength, toLength(lineSeparator), padding, decodingPolicy);
708-
Objects.requireNonNull(encodeTable, "encodeTable");
709-
if (encodeTable.length != STANDARD_ENCODE_TABLE.length) {
693+
private Base64(final Builder builder) {
694+
super(builder);
695+
Objects.requireNonNull(builder.getEncodeTable(), "encodeTable");
696+
if (builder.getEncodeTable().length != STANDARD_ENCODE_TABLE.length) {
710697
throw new IllegalArgumentException("encodeTable must have exactly 64 entries.");
711698
}
712-
// same array first or equal contents second
713-
this.isUrlSafe = encodeTable == URL_SAFE_ENCODE_TABLE || Arrays.equals(encodeTable, URL_SAFE_ENCODE_TABLE);
714-
if (encodeTable == STANDARD_ENCODE_TABLE || this.isUrlSafe) {
715-
decodeTable = DECODE_TABLE;
716-
// No need of a defensive copy of an internal table.
717-
this.encodeTable = encodeTable;
718-
} else {
719-
this.encodeTable = encodeTable.clone();
720-
this.decodeTable = calculateDecodeTable(this.encodeTable);
721-
}
699+
this.isStandardEncodeTable = Arrays.equals(builder.getEncodeTable(), STANDARD_ENCODE_TABLE);
700+
this.isUrlSafe = Arrays.equals(builder.getEncodeTable(), URL_SAFE_ENCODE_TABLE);
701+
this.encodeTable = builder.getEncodeTable();
702+
this.decodeTable = this.isStandardEncodeTable || this.isUrlSafe ? DECODE_TABLE : calculateDecodeTable(this.encodeTable);
722703
// TODO could be simplified if there is no requirement to reject invalid line sep when length <=0
723704
// @see test case Base64Test.testConstructors()
724-
if (lineSeparator != null) {
725-
final byte[] lineSeparatorCopy = lineSeparator.clone();
726-
if (containsAlphabetOrPad(lineSeparatorCopy)) {
727-
final String sep = StringUtils.newStringUtf8(lineSeparatorCopy);
705+
if (builder.getLineSeparator().length > 0) {
706+
final byte[] lineSeparatorB = builder.getLineSeparator();
707+
if (containsAlphabetOrPad(lineSeparatorB)) {
708+
final String sep = StringUtils.newStringUtf8(lineSeparatorB);
728709
throw new IllegalArgumentException("lineSeparator must not contain base64 characters: [" + sep + "]");
729710
}
730-
if (lineLength > 0) { // null line-sep forces no chunking rather than throwing IAE
731-
this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparatorCopy.length;
732-
this.lineSeparator = lineSeparatorCopy;
711+
if (builder.getLineLength() > 0) { // null line-sep forces no chunking rather than throwing IAE
712+
this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparatorB.length;
713+
this.lineSeparator = lineSeparatorB;
733714
} else {
734715
this.encodeSize = BYTES_PER_ENCODED_BLOCK;
735716
this.lineSeparator = null;
@@ -885,7 +866,7 @@ void encode(final byte[] in, int inPos, final int inAvail, final Context context
885866
// remaining 2:
886867
buffer[context.pos++] = encodeTable[context.ibitWorkArea << 4 & MASK_6_BITS];
887868
// URL-SAFE skips the padding to further reduce size.
888-
if (encodeTable == STANDARD_ENCODE_TABLE) {
869+
if (isStandardEncodeTable) {
889870
buffer[context.pos++] = pad;
890871
buffer[context.pos++] = pad;
891872
}
@@ -896,7 +877,7 @@ void encode(final byte[] in, int inPos, final int inAvail, final Context context
896877
buffer[context.pos++] = encodeTable[context.ibitWorkArea >> 4 & MASK_6_BITS];
897878
buffer[context.pos++] = encodeTable[context.ibitWorkArea << 2 & MASK_6_BITS];
898879
// URL-SAFE skips the padding to further reduce size.
899-
if (encodeTable == STANDARD_ENCODE_TABLE) {
880+
if (isStandardEncodeTable) {
900881
buffer[context.pos++] = pad;
901882
}
902883
break;

src/main/java/org/apache/commons/codec/binary/BaseNCodec.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,11 @@ public String toString() {
348348
*/
349349
static final byte[] CHUNK_SEPARATOR = {'\r', '\n'};
350350

351+
/**
352+
* The empty byte array.
353+
*/
354+
static final byte[] EMPTY_BYTE_ARRAY = {};
355+
351356
/**
352357
* Create a positive capacity at least as large the minimum required capacity.
353358
* If the minimum capacity is negative then this throws an OutOfMemoryError as no array

src/test/java/org/apache/commons/codec/binary/Base32Test.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -427,13 +427,12 @@ void testConstructors() {
427427
// even when line length is negative.
428428
base32 = new Base32(-1, new byte[] { 'A' });
429429
base32 = new Base32(32, new byte[] { '$' }); // OK
430-
assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, new Base32(32, null).getLineSeparator(), "null line separator use the default");
430+
assertArrayEquals(new byte[0], new Base32(32, null).getLineSeparator(), "null line separator use an empty array");
431431
assertThrows(IllegalArgumentException.class, () -> new Base32(32, new byte[] { 'A' }), "'A' as a line separator");
432432
assertThrows(IllegalArgumentException.class, () -> new Base32(32, new byte[] { '=' }), "'=' as a line separator");
433433
assertThrows(IllegalArgumentException.class, () -> new Base32(32, new byte[] { 'A', '$' }), "'A$' as a line separator");
434434
assertThrows(IllegalArgumentException.class, () -> new Base32(32, new byte[] { '\n' }, false, (byte) 'A'), "'A' as padding");
435435
assertThrows(IllegalArgumentException.class, () -> new Base32(32, new byte[] { '\n' }, false, (byte) ' '), "' ' as padding");
436-
437436
base32 = new Base32(32, new byte[] { ' ', '$', '\n', '\r', '\t' }); // OK
438437
assertNotNull(base32);
439438
}

src/test/java/org/apache/commons/codec/binary/Base64Test.java

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,17 @@
3131
import java.nio.charset.StandardCharsets;
3232
import java.util.Arrays;
3333
import java.util.Random;
34+
import java.util.stream.Stream;
3435

3536
import org.apache.commons.codec.CodecPolicy;
3637
import org.apache.commons.codec.DecoderException;
3738
import org.apache.commons.codec.EncoderException;
3839
import org.apache.commons.lang3.ArrayUtils;
3940
import org.junit.jupiter.api.Assumptions;
4041
import org.junit.jupiter.api.Test;
42+
import org.junit.jupiter.params.ParameterizedTest;
43+
import org.junit.jupiter.params.provider.Arguments;
44+
import org.junit.jupiter.params.provider.MethodSource;
4145

4246
/**
4347
* Tests {@link Base64}.
@@ -130,6 +134,24 @@ private static void assertBase64DecodingOfTrailingBits(final int nbits) {
130134
}
131135
}
132136

137+
static Stream<Object> testIsBase64() {
138+
// @formatter:off
139+
return Stream.of(
140+
Arguments.of(new byte[] { 1, 2, 3 }, false),
141+
Arguments.of(new byte[] { Byte.MIN_VALUE }, false),
142+
Arguments.of(new byte[] { -125 }, false),
143+
Arguments.of(new byte[] { -10 }, false),
144+
Arguments.of(new byte[] { 0 }, false),
145+
Arguments.of(new byte[] { 64, Byte.MAX_VALUE }, false),
146+
Arguments.of(new byte[] { Byte.MAX_VALUE }, false),
147+
Arguments.of(new byte[] { 'A' }, true),
148+
Arguments.of(new byte[] { 'A', Byte.MIN_VALUE }, false),
149+
Arguments.of(new byte[] { 'A', 'Z', 'a' }, true),
150+
Arguments.of(new byte[] { '/', '=', '+' }, true),
151+
Arguments.of(new byte[] { '$' }, false));
152+
// @formatter:off
153+
}
154+
133155
private final Random random = new Random();
134156

135157
/**
@@ -149,22 +171,16 @@ void testBase64() {
149171
byte[] encodedBytes = Base64.encodeBase64(StringUtils.getBytesUtf8(content));
150172
encodedContent = StringUtils.newStringUtf8(encodedBytes);
151173
assertEquals("SGVsbG8gV29ybGQ=", encodedContent, "encoding hello world");
152-
153-
Base64 b64 = new Base64(BaseNCodec.MIME_CHUNK_SIZE, null); // null
154-
// lineSeparator
155-
// same as
156-
// saying
157-
// no-chunking
174+
// null lineSeparator same as saying no-chunking
175+
Base64 b64 = new Base64(BaseNCodec.MIME_CHUNK_SIZE, null);
158176
encodedBytes = b64.encode(StringUtils.getBytesUtf8(content));
159177
encodedContent = StringUtils.newStringUtf8(encodedBytes);
160178
assertEquals("SGVsbG8gV29ybGQ=", encodedContent, "encoding hello world");
161-
162-
b64 = new Base64(0, null); // null lineSeparator same as saying
163-
// no-chunking
179+
// null lineSeparator same as saying no-chunking
180+
b64 = new Base64(0, null);
164181
encodedBytes = b64.encode(StringUtils.getBytesUtf8(content));
165182
encodedContent = StringUtils.newStringUtf8(encodedBytes);
166183
assertEquals("SGVsbG8gV29ybGQ=", encodedContent, "encoding hello world");
167-
168184
// bogus characters to decode (to skip actually) {e-acute*6}
169185
final byte[] decode = b64.decode("SGVsbG{\u00e9\u00e9\u00e9\u00e9\u00e9\u00e9}8gV29ybGQ=");
170186
final String decodeString = StringUtils.newStringUtf8(decode);
@@ -692,23 +708,16 @@ void testIgnoringNonBase64InDecode() throws Exception {
692708
assertEquals(FOX_TEXT, new String(Base64.decodeBase64(FOX_BASE64.getBytes(CHARSET_UTF8))));
693709
}
694710

695-
@Test
696-
void testIsArrayByteBase64() {
697-
assertFalse(Base64.isBase64(new byte[] { Byte.MIN_VALUE }));
698-
assertFalse(Base64.isBase64(new byte[] { -125 }));
699-
assertFalse(Base64.isBase64(new byte[] { -10 }));
700-
assertFalse(Base64.isBase64(new byte[] { 0 }));
701-
assertFalse(Base64.isBase64(new byte[] { 64, Byte.MAX_VALUE }));
702-
assertFalse(Base64.isBase64(new byte[] { Byte.MAX_VALUE }));
703-
704-
assertTrue(Base64.isBase64(new byte[] { 'A' }));
705-
706-
assertFalse(Base64.isBase64(new byte[] { 'A', Byte.MIN_VALUE }));
707-
708-
assertTrue(Base64.isBase64(new byte[] { 'A', 'Z', 'a' }));
709-
assertTrue(Base64.isBase64(new byte[] { '/', '=', '+' }));
711+
@ParameterizedTest
712+
@MethodSource("testIsBase64")
713+
void testIsArrayByteBase64(final byte[] arrayOctet, final boolean match) {
714+
assertEquals(match, Base64.isArrayByteBase64(arrayOctet));
715+
}
710716

711-
assertFalse(Base64.isBase64(new byte[] { '$' }));
717+
@ParameterizedTest
718+
@MethodSource
719+
void testIsBase64(final byte[] arrayOctet, final boolean match) {
720+
assertEquals(match, Base64.isBase64(arrayOctet));
712721
}
713722

714723
/**

0 commit comments

Comments
 (0)