Skip to content

Commit 02235df

Browse files
committed
Add Base32.Builder (allows custom alphabets)
1 parent f6deb13 commit 02235df

4 files changed

Lines changed: 95 additions & 4 deletions

File tree

src/changes/changes.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ The <action> type attribute can be add,update,fix,remove.
4848
<action type="add" dev="ggregory" due-to="Gary Gregory">Add override org.apache.commons.codec.language.bm.Rule.PhonemeExpr.size().</action>
4949
<action type="add" dev="ggregory" due-to="Chris Kocel, Gary Gregory">Add support for Base64 custom alphabets #266.</action>
5050
<action type="add" dev="ggregory" due-to="Gary Gregory">Add Base64.Builder (allows custom alphabets).</action>
51+
<action type="add" dev="ggregory" due-to="Gary Gregory">Add Base32.Builder (allows custom alphabets).</action>
5152
<!-- FIX -->
5253
<action type="fix" dev="ggregory" due-to="Gary Gregory">Optimize memory allocation in PhoneticEngine.</action>
5354
<action type="fix" dev="ggregory" due-to="Gary Gregory">BCodec and QCodec encode() methods throw UnsupportedCharsetException instead of EncoderException.</action>

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

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,49 @@
4242
*/
4343
public class Base32 extends BaseNCodec {
4444

45+
/**
46+
* Builds {@link Base32} instances.
47+
*
48+
* @since 1.17.0
49+
*/
50+
public static class Builder extends AbstractBuilder<Base32, Builder> {
51+
52+
/** Padding byte. */
53+
private byte padding = PAD_DEFAULT;
54+
55+
/**
56+
* Constructs a new instance.
57+
*/
58+
public Builder() {
59+
super(ENCODE_TABLE);
60+
}
61+
62+
@Override
63+
public Base32 get() {
64+
return new Base32(getLineLength(), getLineSeparator(), getEncodeTable(), padding, getDecodingPolicy());
65+
}
66+
67+
/**
68+
* Sets the padding byte.
69+
*
70+
* @param padding the padding byte.
71+
* @return this.
72+
*/
73+
public Builder setPadding(final byte padding) {
74+
this.padding = padding;
75+
return this;
76+
}
77+
78+
}
79+
4580
/**
4681
* BASE32 characters are 5 bits in length. They are formed by taking a block of five octets to form a 40-bit string, which is converted into eight BASE32
4782
* characters.
4883
*/
4984
private static final int BITS_PER_ENCODED_BYTE = 5;
85+
5086
private static final int BYTES_PER_ENCODED_BLOCK = 8;
5187
private static final int BYTES_PER_UNENCODED_BLOCK = 5;
52-
5388
/**
5489
* This array is a lookup table that translates Unicode characters drawn from the "Base32 Alphabet" (as specified in Table 3 of RFC 4648) into their 5-bit
5590
* positive integer equivalents. Characters that are not in the Base32 alphabet but fall within the bounds of the array are translated to -1.
@@ -127,6 +162,16 @@ public class Base32 extends BaseNCodec {
127162
/** Mask used to extract 1 bits, used when decoding final trailing character. */
128163
private static final long MASK_1BITS = 0x01L;
129164

165+
/**
166+
* Creates a new Builder.
167+
*
168+
* @return a new Builder.
169+
* @since 1.17.0
170+
*/
171+
public static Builder builder() {
172+
return new Builder();
173+
}
174+
130175
// The static final fields above are used for the original static byte[] methods on Base32.
131176
// The private member fields below are used with the new streaming approach, which requires
132177
// some state be preserved between calls of encode() and decode().
@@ -262,7 +307,7 @@ public Base32(final int lineLength, final byte[] lineSeparator, final boolean us
262307
* then the output will not be divided into lines (chunks). Ignored when decoding.
263308
* @param lineSeparator Each line of encoded data will end with this sequence of bytes.
264309
* @param useHex if {@code true}, then use Base32 Hex alphabet, otherwise use Base32 alphabet
265-
* @param padding byte used as padding byte.
310+
* @param padding padding byte.
266311
* @throws IllegalArgumentException Thrown when the {@code lineSeparator} contains Base32 characters. Or the lineLength &gt; 0 and lineSeparator is null.
267312
*/
268313
public Base32(final int lineLength, final byte[] lineSeparator, final boolean useHex, final byte padding) {
@@ -282,7 +327,7 @@ public Base32(final int lineLength, final byte[] lineSeparator, final boolean us
282327
* then the output will not be divided into lines (chunks). Ignored when decoding.
283328
* @param lineSeparator Each line of encoded data will end with this sequence of bytes.
284329
* @param useHex if {@code true}, then use Base32 Hex alphabet, otherwise use Base32 alphabet
285-
* @param padding byte used as padding byte.
330+
* @param padding padding byte.
286331
* @param decodingPolicy The decoding policy.
287332
* @throws IllegalArgumentException Thrown when the {@code lineSeparator} contains Base32 characters. Or the lineLength &gt; 0 and lineSeparator is null.
288333
* @since 1.15
@@ -304,7 +349,7 @@ public Base32(final int lineLength, final byte[] lineSeparator, final boolean us
304349
* then the output will not be divided into lines (chunks). Ignored when decoding.
305350
* @param lineSeparator Each line of encoded data will end with this sequence of bytes.
306351
* @param encodeTable A Base32 alphabet.
307-
* @param padding byte used as padding byte.
352+
* @param padding padding byte.
308353
* @param decodingPolicy The decoding policy.
309354
* @throws IllegalArgumentException Thrown when the {@code lineSeparator} contains Base32 characters. Or the lineLength &gt; 0 and lineSeparator is null.
310355
*/
@@ -554,6 +599,15 @@ void encode(final byte[] input, int inPos, final int inAvail, final Context cont
554599
}
555600
}
556601

602+
/**
603+
* Gets the line separator (for testing only).
604+
*
605+
* @return the line separator.
606+
*/
607+
byte[] getLineSeparator() {
608+
return lineSeparator;
609+
}
610+
557611
/**
558612
* Returns whether or not the {@code octet} is in the Base32 alphabet.
559613
*

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,7 @@ public Builder setUrlSafe(final boolean urlSafe) {
166166
private static final int MASK_4BITS = 0xf;
167167
/** Mask used to extract 2 bits, used when decoding final trailing character. */
168168
private static final int MASK_2BITS = 0x3;
169+
169170
/**
170171
* Creates a new Builder.
171172
*

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,41 @@ public void testBase32SamplesNonDefaultPadding() throws Exception {
355355
}
356356
}
357357

358+
@Test
359+
public void testBuilderCodecPolicy() {
360+
assertEquals(CodecPolicy.LENIENT, Base32.builder().get().getCodecPolicy());
361+
assertEquals(CodecPolicy.LENIENT, Base32.builder().setDecodingPolicy(CodecPolicy.LENIENT).get().getCodecPolicy());
362+
assertEquals(CodecPolicy.STRICT, Base32.builder().setDecodingPolicy(CodecPolicy.STRICT).get().getCodecPolicy());
363+
assertEquals(CodecPolicy.LENIENT, Base32.builder().setDecodingPolicy(CodecPolicy.STRICT).setDecodingPolicy(null).get().getCodecPolicy());
364+
assertEquals(CodecPolicy.LENIENT, Base32.builder().setDecodingPolicy(null).get().getCodecPolicy());
365+
}
366+
367+
@Test
368+
public void testBuilderLineAttributes() {
369+
assertNull(Base32.builder().get().getLineSeparator());
370+
assertNull(Base32.builder().setLineSeparator(BaseNCodec.CHUNK_SEPARATOR).get().getLineSeparator());
371+
assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(4).setLineSeparator(BaseNCodec.CHUNK_SEPARATOR).get().getLineSeparator());
372+
assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(4).setLineSeparator(null).get().getLineSeparator());
373+
assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(10).setLineSeparator(null).get().getLineSeparator());
374+
assertNull(Base32.builder().setLineLength(-1).setLineSeparator(null).get().getLineSeparator());
375+
assertNull(Base32.builder().setLineLength(0).setLineSeparator(null).get().getLineSeparator());
376+
assertArrayEquals(new byte[] { 1 }, Base32.builder().setLineLength(4).setLineSeparator((byte) 1).get().getLineSeparator());
377+
assertEquals("MZXXQ===", Base32.builder().setLineLength(4).get().encodeToString("fox".getBytes(CHARSET_UTF8)));
378+
}
379+
380+
@Test
381+
public void testBuilderPadingByte() {
382+
assertNull(Base32.builder().get().getLineSeparator());
383+
assertNull(Base32.builder().setLineSeparator(BaseNCodec.CHUNK_SEPARATOR).get().getLineSeparator());
384+
assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(4).setLineSeparator(BaseNCodec.CHUNK_SEPARATOR).get().getLineSeparator());
385+
assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(4).setLineSeparator(null).get().getLineSeparator());
386+
assertArrayEquals(BaseNCodec.CHUNK_SEPARATOR, Base32.builder().setLineLength(10).setLineSeparator(null).get().getLineSeparator());
387+
assertNull(Base32.builder().setLineLength(-1).setLineSeparator(null).get().getLineSeparator());
388+
assertNull(Base32.builder().setLineLength(0).setLineSeparator(null).get().getLineSeparator());
389+
assertArrayEquals(new byte[] { 1 }, Base32.builder().setLineLength(4).setLineSeparator((byte) 1).get().getLineSeparator());
390+
assertEquals("MZXXQ___", Base32.builder().setLineLength(4).setPadding((byte) '_').get().encodeToString("fox".getBytes(CHARSET_UTF8)));
391+
}
392+
358393
@Test
359394
public void testCodec200() {
360395
final Base32 codec = new Base32(true, (byte) 'W'); // should be allowed

0 commit comments

Comments
 (0)