1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.codec.binary;
19
20 import java.util.Objects;
21
22 import org.apache.commons.codec.CodecPolicy;
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 public class Base32 extends BaseNCodec {
58
59
60
61
62
63
64 public static class Builder extends AbstractBuilder<Base32, Builder> {
65
66
67
68
69 public Builder() {
70 super(ENCODE_TABLE);
71 }
72
73 @Override
74 public Base32 get() {
75 return new Base32(getLineLength(), getLineSeparator(), getEncodeTable(), getPadding(), getDecodingPolicy());
76 }
77
78 }
79
80
81
82
83
84 private static final int BITS_PER_ENCODED_BYTE = 5;
85
86 private static final int BYTES_PER_ENCODED_BLOCK = 8;
87 private static final int BYTES_PER_UNENCODED_BLOCK = 5;
88
89
90
91
92
93 private static final byte[] DECODE_TABLE = {
94
95 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
96 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
97 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
98 -1, -1, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1,
99 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
100 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
101 -1, -1, -1, -1, -1,
102 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
103 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
104 };
105
106
107
108
109
110
111
112 private static final byte[] ENCODE_TABLE = {
113 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
114 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
115 '2', '3', '4', '5', '6', '7',
116 };
117
118
119
120
121
122
123
124 private static final byte[] HEX_DECODE_TABLE = {
125
126 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
127 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
128 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
129 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
130 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
131 25, 26, 27, 28, 29, 30, 31,
132 -1, -1, -1, -1, -1, -1, -1, -1, -1,
133 -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
134 25, 26, 27, 28, 29, 30, 31
135 };
136
137
138
139
140
141
142
143 private static final byte[] HEX_ENCODE_TABLE = {
144 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
145 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
146 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
147 };
148
149
150
151 private static final int MASK_5BITS = 0x1f;
152
153
154 private static final long MASK_4BITS = 0x0fL;
155
156
157 private static final long MASK_3BITS = 0x07L;
158
159
160 private static final long MASK_2BITS = 0x03L;
161
162
163 private static final long MASK_1BITS = 0x01L;
164
165
166
167
168
169
170
171 public static Builder builder() {
172 return new Builder();
173 }
174
175
176
177
178
179
180
181
182 private final byte[] decodeTable;
183
184
185
186
187
188 private final int encodeSize;
189
190
191
192
193 private final byte[] encodeTable;
194
195
196
197
198 private final byte[] lineSeparator;
199
200
201
202
203
204
205
206 public Base32() {
207 this(false);
208 }
209
210
211
212
213
214
215
216
217
218 public Base32(final boolean useHex) {
219 this(0, null, useHex, PAD_DEFAULT);
220 }
221
222
223
224
225
226
227
228
229
230
231 public Base32(final boolean useHex, final byte padding) {
232 this(0, null, useHex, padding);
233 }
234
235
236
237
238
239
240
241
242
243 public Base32(final byte pad) {
244 this(false, pad);
245 }
246
247
248
249
250
251
252
253
254
255
256 public Base32(final int lineLength) {
257 this(lineLength, CHUNK_SEPARATOR);
258 }
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274 public Base32(final int lineLength, final byte[] lineSeparator) {
275 this(lineLength, lineSeparator, false, PAD_DEFAULT);
276 }
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293 public Base32(final int lineLength, final byte[] lineSeparator, final boolean useHex) {
294 this(lineLength, lineSeparator, useHex, PAD_DEFAULT);
295 }
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313 public Base32(final int lineLength, final byte[] lineSeparator, final boolean useHex, final byte padding) {
314 this(lineLength, lineSeparator, useHex, padding, DECODING_POLICY_DEFAULT);
315 }
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335 public Base32(final int lineLength, final byte[] lineSeparator, final boolean useHex, final byte padding, final CodecPolicy decodingPolicy) {
336 this(lineLength, lineSeparator, useHex ? HEX_ENCODE_TABLE : ENCODE_TABLE, padding, decodingPolicy);
337 }
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356 private Base32(final int lineLength, final byte[] lineSeparator, final byte[] encodeTable, final byte padding, final CodecPolicy decodingPolicy) {
357 super(BYTES_PER_UNENCODED_BLOCK, BYTES_PER_ENCODED_BLOCK, lineLength, toLength(lineSeparator), padding, decodingPolicy);
358 Objects.requireNonNull(encodeTable, "encodeTable");
359 this.encodeTable = encodeTable;
360 this.decodeTable = encodeTable == HEX_ENCODE_TABLE ? HEX_DECODE_TABLE : DECODE_TABLE;
361 if (lineLength > 0) {
362 if (lineSeparator == null) {
363 throw new IllegalArgumentException("lineLength " + lineLength + " > 0, but lineSeparator is null");
364 }
365 final byte[] lineSeparatorCopy = lineSeparator.clone();
366
367 if (containsAlphabetOrPad(lineSeparatorCopy)) {
368 final String sep = StringUtils.newStringUtf8(lineSeparatorCopy);
369 throw new IllegalArgumentException("lineSeparator must not contain Base32 characters: [" + sep + "]");
370 }
371 this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparatorCopy.length;
372 this.lineSeparator = lineSeparatorCopy;
373 } else {
374 this.encodeSize = BYTES_PER_ENCODED_BLOCK;
375 this.lineSeparator = null;
376 }
377 if (isInAlphabet(padding) || Character.isWhitespace(padding)) {
378 throw new IllegalArgumentException("pad must not be in alphabet or whitespace");
379 }
380 }
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401 @Override
402 void decode(final byte[] input, int inPos, final int inAvail, final Context context) {
403
404 if (context.eof) {
405 return;
406 }
407 if (inAvail < 0) {
408 context.eof = true;
409 }
410 final int decodeSize = this.encodeSize - 1;
411 for (int i = 0; i < inAvail; i++) {
412 final byte b = input[inPos++];
413 if (b == pad) {
414
415 context.eof = true;
416 break;
417 }
418 final byte[] buffer = ensureBufferSize(decodeSize, context);
419 if (b >= 0 && b < this.decodeTable.length) {
420 final int result = this.decodeTable[b];
421 if (result >= 0) {
422 context.modulus = (context.modulus + 1) % BYTES_PER_ENCODED_BLOCK;
423
424 context.lbitWorkArea = (context.lbitWorkArea << BITS_PER_ENCODED_BYTE) + result;
425 if (context.modulus == 0) {
426 buffer[context.pos++] = (byte) (context.lbitWorkArea >> 32 & MASK_8BITS);
427 buffer[context.pos++] = (byte) (context.lbitWorkArea >> 24 & MASK_8BITS);
428 buffer[context.pos++] = (byte) (context.lbitWorkArea >> 16 & MASK_8BITS);
429 buffer[context.pos++] = (byte) (context.lbitWorkArea >> 8 & MASK_8BITS);
430 buffer[context.pos++] = (byte) (context.lbitWorkArea & MASK_8BITS);
431 }
432 }
433 }
434 }
435
436
437
438 if (context.eof && context.modulus > 0) {
439 final byte[] buffer = ensureBufferSize(decodeSize, context);
440
441
442
443
444
445
446 switch (context.modulus) {
447
448 case 1:
449 validateTrailingCharacters();
450 case 2:
451 validateCharacter(MASK_2BITS, context);
452 buffer[context.pos++] = (byte) (context.lbitWorkArea >> 2 & MASK_8BITS);
453 break;
454 case 3:
455 validateTrailingCharacters();
456
457 buffer[context.pos++] = (byte) (context.lbitWorkArea >> 7 & MASK_8BITS);
458 break;
459 case 4:
460 validateCharacter(MASK_4BITS, context);
461 context.lbitWorkArea = context.lbitWorkArea >> 4;
462 buffer[context.pos++] = (byte) (context.lbitWorkArea >> 8 & MASK_8BITS);
463 buffer[context.pos++] = (byte) (context.lbitWorkArea & MASK_8BITS);
464 break;
465 case 5:
466 validateCharacter(MASK_1BITS, context);
467 context.lbitWorkArea = context.lbitWorkArea >> 1;
468 buffer[context.pos++] = (byte) (context.lbitWorkArea >> 16 & MASK_8BITS);
469 buffer[context.pos++] = (byte) (context.lbitWorkArea >> 8 & MASK_8BITS);
470 buffer[context.pos++] = (byte) (context.lbitWorkArea & MASK_8BITS);
471 break;
472 case 6:
473 validateTrailingCharacters();
474
475 context.lbitWorkArea = context.lbitWorkArea >> 6;
476 buffer[context.pos++] = (byte) (context.lbitWorkArea >> 16 & MASK_8BITS);
477 buffer[context.pos++] = (byte) (context.lbitWorkArea >> 8 & MASK_8BITS);
478 buffer[context.pos++] = (byte) (context.lbitWorkArea & MASK_8BITS);
479 break;
480 case 7:
481 validateCharacter(MASK_3BITS, context);
482 context.lbitWorkArea = context.lbitWorkArea >> 3;
483 buffer[context.pos++] = (byte) (context.lbitWorkArea >> 24 & MASK_8BITS);
484 buffer[context.pos++] = (byte) (context.lbitWorkArea >> 16 & MASK_8BITS);
485 buffer[context.pos++] = (byte) (context.lbitWorkArea >> 8 & MASK_8BITS);
486 buffer[context.pos++] = (byte) (context.lbitWorkArea & MASK_8BITS);
487 break;
488 default:
489
490 throw new IllegalStateException("Impossible modulus " + context.modulus);
491 }
492 }
493 }
494
495
496
497
498
499
500
501
502
503
504
505
506 @Override
507 void encode(final byte[] input, int inPos, final int inAvail, final Context context) {
508
509 if (context.eof) {
510 return;
511 }
512
513
514 if (inAvail < 0) {
515 context.eof = true;
516 if (0 == context.modulus && lineLength == 0) {
517 return;
518 }
519 final byte[] buffer = ensureBufferSize(encodeSize, context);
520 final int savedPos = context.pos;
521 switch (context.modulus) {
522 case 0:
523 break;
524 case 1:
525 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 3) & MASK_5BITS];
526 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea << 2) & MASK_5BITS];
527 buffer[context.pos++] = pad;
528 buffer[context.pos++] = pad;
529 buffer[context.pos++] = pad;
530 buffer[context.pos++] = pad;
531 buffer[context.pos++] = pad;
532 buffer[context.pos++] = pad;
533 break;
534 case 2:
535 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 11) & MASK_5BITS];
536 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 6) & MASK_5BITS];
537 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 1) & MASK_5BITS];
538 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea << 4) & MASK_5BITS];
539 buffer[context.pos++] = pad;
540 buffer[context.pos++] = pad;
541 buffer[context.pos++] = pad;
542 buffer[context.pos++] = pad;
543 break;
544 case 3:
545 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 19) & MASK_5BITS];
546 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 14) & MASK_5BITS];
547 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 9) & MASK_5BITS];
548 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 4) & MASK_5BITS];
549 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea << 1) & MASK_5BITS];
550 buffer[context.pos++] = pad;
551 buffer[context.pos++] = pad;
552 buffer[context.pos++] = pad;
553 break;
554 case 4:
555 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 27) & MASK_5BITS];
556 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 22) & MASK_5BITS];
557 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 17) & MASK_5BITS];
558 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 12) & MASK_5BITS];
559 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 7) & MASK_5BITS];
560 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 2) & MASK_5BITS];
561 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea << 3) & MASK_5BITS];
562 buffer[context.pos++] = pad;
563 break;
564 default:
565 throw new IllegalStateException("Impossible modulus " + context.modulus);
566 }
567 context.currentLinePos += context.pos - savedPos;
568
569 if (lineLength > 0 && context.currentLinePos > 0) {
570 System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length);
571 context.pos += lineSeparator.length;
572 }
573 } else {
574 for (int i = 0; i < inAvail; i++) {
575 final byte[] buffer = ensureBufferSize(encodeSize, context);
576 context.modulus = (context.modulus + 1) % BYTES_PER_UNENCODED_BLOCK;
577 int b = input[inPos++];
578 if (b < 0) {
579 b += 256;
580 }
581 context.lbitWorkArea = (context.lbitWorkArea << 8) + b;
582 if (0 == context.modulus) {
583 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 35) & MASK_5BITS];
584 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 30) & MASK_5BITS];
585 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 25) & MASK_5BITS];
586 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 20) & MASK_5BITS];
587 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 15) & MASK_5BITS];
588 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 10) & MASK_5BITS];
589 buffer[context.pos++] = encodeTable[(int) (context.lbitWorkArea >> 5) & MASK_5BITS];
590 buffer[context.pos++] = encodeTable[(int) context.lbitWorkArea & MASK_5BITS];
591 context.currentLinePos += BYTES_PER_ENCODED_BLOCK;
592 if (lineLength > 0 && lineLength <= context.currentLinePos) {
593 System.arraycopy(lineSeparator, 0, buffer, context.pos, lineSeparator.length);
594 context.pos += lineSeparator.length;
595 context.currentLinePos = 0;
596 }
597 }
598 }
599 }
600 }
601
602
603
604
605
606
607 byte[] getLineSeparator() {
608 return lineSeparator;
609 }
610
611
612
613
614
615
616
617 @Override
618 public boolean isInAlphabet(final byte octet) {
619 return octet >= 0 && octet < decodeTable.length && decodeTable[octet] != -1;
620 }
621
622
623
624
625
626
627
628
629
630
631
632
633
634 private void validateCharacter(final long emptyBitsMask, final Context context) {
635
636 if (isStrictDecoding() && (context.lbitWorkArea & emptyBitsMask) != 0) {
637 throw new IllegalArgumentException("Strict decoding: Last encoded character (before the paddings if any) is a valid " +
638 "base 32 alphabet but not a possible encoding. Expected the discarded bits from the character to be zero.");
639 }
640 }
641
642
643
644
645
646
647 private void validateTrailingCharacters() {
648 if (isStrictDecoding()) {
649 throw new IllegalArgumentException("Strict decoding: Last encoded character(s) (before the paddings if any) are valid " +
650 "base 32 alphabet but not a possible encoding. Decoding requires either 2, 4, 5, or 7 trailing 5-bit characters to create bytes.");
651 }
652 }
653 }