Skip to content

Commit ebe805a

Browse files
committed
Base64 constructor makes a defensive copy of a custom alphabet array
1 parent 5504333 commit ebe805a

2 files changed

Lines changed: 24 additions & 23 deletions

File tree

src/changes/changes.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ The <action> type attribute can be add,update,fix,remove.
4949
<action type="fix" dev="ggregory" due-to="Gary Gregory">Optimize memory allocation in PhoneticEngine.</action>
5050
<action type="fix" dev="ggregory" due-to="Gary Gregory">BCodec and QCodec encode() methods throw UnsupportedCharsetException instead of EncoderException.</action>
5151
<action type="fix" dev="ggregory" due-to="Gary Gregory">Set Javadoc link to latest Java API LTS version.</action>
52-
<action type="fix" dev="ggregory" due-to="Gary Gregory">Base64 constructor makes a better defensive copy of the line separator array.</action>
52+
<action type="fix" dev="ggregory" due-to="Gary Gregory">Base64 constructor makes a defensive copy of the line separator array.</action>
53+
<action type="fix" dev="ggregory" due-to="Gary Gregory">Base64 constructor makes a defensive copy of a custom alphabet array.</action>
5354
<!-- ADD -->
5455
<action type="add" dev="ggregory" due-to="Gary Gregory">Add override org.apache.commons.codec.language.bm.Rule.PhonemeExpr.size().</action>
5556
<action type="add" dev="ggregory" due-to="Chris Kocel, Gary Gregory">Add support for Base64 custom alphabets #266.</action>

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

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -498,6 +498,8 @@ private static byte[] toUrlSafeEncodeTable(final boolean urlSafe) {
498498
*/
499499
private final int encodeSize;
500500

501+
private final boolean isUrlSafe;
502+
501503
/**
502504
* Constructs a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
503505
* <p>
@@ -646,8 +648,7 @@ public Base64(final int lineLength, final byte[] lineSeparator, final boolean ur
646648
/**
647649
* Constructs a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
648650
* <p>
649-
* When encoding the line length and line separator are given in the constructor, and the encoding table is
650-
* STANDARD_ENCODE_TABLE.
651+
* When encoding the line length and line separator are given in the constructor, and the encoding table is STANDARD_ENCODE_TABLE.
651652
* </p>
652653
* <p>
653654
* Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
@@ -656,29 +657,28 @@ public Base64(final int lineLength, final byte[] lineSeparator, final boolean ur
656657
* When decoding all variants are supported.
657658
* </p>
658659
*
659-
* @param lineLength
660-
* Each line of encoded data will be at most of the given length (rounded down to the nearest multiple of
661-
* 4). If lineLength &lt;= 0, then the output will not be divided into lines (chunks). Ignored when
662-
* decoding.
663-
* @param lineSeparator
664-
* Each line of encoded data will end with this sequence of bytes; the constructor makes a defensive copy.
665-
* @param padding padding byte.
666-
* @param encodeTable
667-
* The manual encodeTable - a byte array of 64 chars.
660+
* @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,
661+
* then the output will not be divided into lines (chunks). Ignored when decoding.
662+
* @param lineSeparator Each line of encoded data will end with this sequence of bytes; the constructor makes a defensive copy. May be null.
663+
* @param padding padding byte.
664+
* @param encodeTable The manual encodeTable - a byte array of 64 chars.
668665
* @param decodingPolicy The decoding policy.
669-
* @throws IllegalArgumentException
670-
* Thrown when the {@code lineSeparator} contains Base64 characters.
666+
* @throws IllegalArgumentException Thrown when the {@code lineSeparator} contains Base64 characters.
671667
*/
672668
private Base64(final int lineLength, final byte[] lineSeparator, final byte padding, final byte[] encodeTable, final CodecPolicy decodingPolicy) {
673669
super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, lineLength, toLength(lineSeparator), padding, decodingPolicy);
674-
this.encodeTable = Objects.requireNonNull(encodeTable, "encodeTable");
675-
if (encodeTable == STANDARD_ENCODE_TABLE || encodeTable == URL_SAFE_ENCODE_TABLE) {
670+
Objects.requireNonNull(encodeTable, "encodeTable");
671+
if (encodeTable.length != ALPHABET_LENGTH) {
672+
throw new IllegalArgumentException("encodeTable must have exactly 64 entries.");
673+
}
674+
this.isUrlSafe = encodeTable == URL_SAFE_ENCODE_TABLE;
675+
if (encodeTable == STANDARD_ENCODE_TABLE || this.isUrlSafe) {
676676
decodeTable = DECODE_TABLE;
677+
// No need of a defensive copy of an internal table.
678+
this.encodeTable = encodeTable;
677679
} else {
678-
if (encodeTable.length != ALPHABET_LENGTH) {
679-
throw new IllegalArgumentException("encodeTable must have exactly 64 entries.");
680-
}
681-
decodeTable = calculateDecodeTable(encodeTable);
680+
this.encodeTable = encodeTable.clone();
681+
this.decodeTable = calculateDecodeTable(this.encodeTable);
682682
}
683683
// TODO could be simplified if there is no requirement to reject invalid line sep when length <=0
684684
// @see test case Base64Test.testConstructors()
@@ -919,13 +919,13 @@ protected boolean isInAlphabet(final byte octet) {
919919
}
920920

921921
/**
922-
* Returns our current encode mode. True if we're URL-SAFE, false otherwise.
922+
* Returns our current encode mode. True if we're URL-safe, false otherwise.
923923
*
924-
* @return true if we're in URL-SAFE mode, false otherwise.
924+
* @return true if we're in URL-safe mode, false otherwise.
925925
* @since 1.4
926926
*/
927927
public boolean isUrlSafe() {
928-
return this.encodeTable == URL_SAFE_ENCODE_TABLE;
928+
return isUrlSafe;
929929
}
930930

931931
/**

0 commit comments

Comments
 (0)