/*
test for https://github.com/kuresaru/base32/blob/97456d5162eb3ba8ddd4b418a6ad3d0afbe5df7e/src/org/arrowfield/Base32.java
the problem is fixed
*/
import java.util.Arrays;
class Main {
/**
* エンコードに使う文字リスト。
*/
protected static final char[] chars32 = { 'A', 'B', 'C', 'D', 'E', 'F',
'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U',
'V', 'W', 'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7', '8', '9' };
/**
* エンコード後の1文字から整数に変換する。
*
* @param in
* エンコード後の文字列に含まれる文字
* @return 変換後の値を int 型で返す。
*/
private static int char2int(char in) {
in = Character.toLowerCase(in);
switch (in) {
case 'a':
return 0;
case 'b':
return 1;
case 'c':
return 2;
case 'd':
return 3;
case 'e':
return 4;
case 'f':
return 5;
case 'g':
return 6;
case 'h':
return 7;
case 'j':
return 8;
case 'k':
return 9;
case 'l':
return 10;
case 'm':
return 11;
case 'n':
return 12;
case 'p':
return 13;
case 'q':
return 14;
case 'r':
return 15;
case 's':
return 16;
case 't':
return 17;
case 'u':
return 18;
case 'v':
return 19;
case 'w':
return 20;
case 'x':
return 21;
case 'y':
return 22;
case 'z':
return 23;
case '2':
return 24;
case '3':
return 25;
case '4':
return 26;
case '5':
return 27;
case '6':
return 28;
case '7':
return 29;
case '8':
return 30;
case '9':
return 31;
case ':':
case ';':
case '<':
case '=':
case '>':
case '?':
case '@':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
case '[':
case '\\':
case ']':
case '^':
case '_':
case '`':
case 'i':
case 'o':
}
return 0;
}
/**
* BASE32にエンコードする
*
* @param エンコードする平文
* @return エンコードされたBase32文字列
*/
public static String encode(byte[] input) {
byte[] binary = input.length % 5 == 0 ? input : Arrays.copyOf(input,
input.length + 5 - input.length % 5);
int cursor = 0;
char[] result = new char[binary.length / 5 * 8];
while ((cursor + 1) * 5 <= binary.length) {
long pack = (((long) binary[cursor * 5] << 32) & 0x000000ff00000000l)
| (((long) binary[cursor * 5 + 1] << 24) & 0x00000000ff000000l)
| (((long) binary[cursor * 5 + 2] << 16) & 0x0000000000ff0000l)
| (((long) binary[cursor * 5 + 3] << 8) & 0x000000000000ff00l)
| ((long) binary[cursor * 5 + 4] & 0x00000000000000ffl);
result[cursor * 8] = chars32[(int) (pack >>> 35) & 0x0000001f];
result[cursor * 8 + 1] = chars32[(int) (pack >>> 30) & 0x0000001f];
result[cursor * 8 + 2] = chars32[(int) (pack >>> 25) & 0x0000001f];
result[cursor * 8 + 3] = chars32[(int) (pack >>> 20) & 0x0000001f];
result[cursor * 8 + 4] = chars32[(int) (pack >>> 15) & 0x0000001f];
result[cursor * 8 + 5] = chars32[(int) (pack >>> 10) & 0x0000001f];
result[cursor * 8 + 6] = chars32[(int) (pack >>> 5) & 0x0000001f];
result[cursor * 8 + 7] = chars32[(int) pack & 0x0000001f];
cursor++;
}
switch (input.length % 5) {
case 0:
return new String(result);
case 1:
return new String(Arrays.copyOf(result, result.length - 6));
case 2:
return new String(Arrays.copyOf(result, result.length - 4));
case 3:
return new String(Arrays.copyOf(result, result.length - 3));
case 4:
return new String(Arrays.copyOf(result, result.length - 1));
}
return null;
}
/**
* BASE32をデコードする。パディングはあってはならない。認識できない文字は「0」となる。引数の文字長が不正の場合はnullが帰る。
*
* @param エンコードされた文字列
* @return デコードした平文
*/
public static byte[] decode(String encoded) {
String input = encoded.length() % 8 == 0 ? encoded : encoded
+ "0000000".substring(0, 8 - encoded.length() % 8);
int cursor = 0;
byte[] result = new byte[input.length() / 8 * 5];
while (input.length() > cursor * 8) {
result[cursor * 5] = (byte) ((char2int(input.charAt(cursor * 8)) << 3 & 0x000000f8) | (char2int(input
.charAt(cursor * 8 + 1)) >>> 2 & 0x00000007));
result[cursor * 5 + 1] = (byte) ((char2int(input
.charAt(cursor * 8 + 1)) << 6 & 0x000000c0)
| (char2int(input.charAt(cursor * 8 + 2)) << 1 & 0x00000003e) | (char2int(input
.charAt(cursor * 8 + 3)) >>> 4 & 0x00000001));
result[cursor * 5 + 2] = (byte) ((char2int(input
.charAt(cursor * 8 + 3)) << 4 & 0x000000f0) | (char2int(input
.charAt(cursor * 8 + 4)) >>> 1 & 0x0000000f));
result[cursor * 5 + 3] = (byte) ((char2int(input
.charAt(cursor * 8 + 4)) << 7 & 0x00000080)
| (char2int(input.charAt(cursor * 8 + 5)) << 2 & 0x00000007c) | (char2int(input
.charAt(cursor * 8 + 6)) >>> 3 & 0x00000003));
result[cursor * 5 + 4] = (byte) ((char2int(input
.charAt(cursor * 8 + 6)) << 5 & 0x000000e0) | (char2int(input
.charAt(cursor * 8 + 7)) & 0x0000001f));
cursor++;
}
switch (encoded.length() % 8) {
case 0:
return result;
case 1:
return null;
case 2:
return Arrays.copyOf(result, result.length - 4);
case 3:
return null;
case 4:
return Arrays.copyOf(result, result.length - 3);
case 5:
return Arrays.copyOf(result, result.length - 2);
case 6:
return null;
case 7:
return Arrays.copyOf(result, result.length - 1);
}
return null;
}
public static void main(String[] args) {
String a = "90";
String b = encode(a.getBytes());
String c = new String(decode(b));
System.out.printf("%s %s %s%n", b, a, c);
}
}