13 | * This is free and unencumbered public domain software 14 | *
15 | * Source: https://github.com/opencoinage/opencoinage/blob/master/src/java/org/opencoinage/util/Base62.java
16 | */
17 | class Base62 {
18 |
19 | private static final BigInteger BASE = BigInteger.valueOf(62);
20 | private static final String DIGITS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
21 |
22 | /**
23 | * Encodes a number using Base62 encoding.
24 | *
25 | * @param number a positive integer
26 | * @return a Base62 string
27 | *
28 | * @throws IllegalArgumentException if
9 | * https://gist.github.com/drmalex07/9008c611ffde6cb2ef3a2db8668bc251
10 | */
11 | class BigIntegerPairing {
12 |
13 | private static final BigInteger HALF = BigInteger.ONE.shiftLeft(64); // 2^64
14 | private static final BigInteger MAX_LONG = BigInteger.valueOf(Long.MAX_VALUE);
15 |
16 | private static Functionnumber
is a negative integer
29 | */
30 | static String encode(BigInteger number) {
31 | if (number.compareTo(BigInteger.ZERO) < 0) {
32 | throwIllegalArgumentException("number must not be negative");
33 | }
34 | StringBuilder result = new StringBuilder();
35 | while (number.compareTo(BigInteger.ZERO) > 0) {
36 | BigInteger[] divmod = number.divideAndRemainder(BASE);
37 | number = divmod[0];
38 | int digit = divmod[1].intValue();
39 | result.insert(0, DIGITS.charAt(digit));
40 | }
41 | return (result.length() == 0) ? DIGITS.substring(0, 1) : result.toString();
42 | }
43 |
44 | private static BigInteger throwIllegalArgumentException(String format, Object... args) {
45 | throw new IllegalArgumentException(String.format(format, args));
46 | }
47 |
48 | /**
49 | * Decodes a string using Base62 encoding.
50 | *
51 | * @param string a Base62 string
52 | * @return a positive integer
53 | *
54 | * @throws IllegalArgumentException if string
is empty
55 | */
56 | static BigInteger decode(final String string) {
57 | return decode(string, 128);
58 | }
59 |
60 | static BigInteger decode(final String string, int bitLimit) {
61 | requireNonNull(string, "Decoded string must not be null");
62 | if (string.length() == 0) {
63 | return throwIllegalArgumentException("String '%s' must not be empty", string);
64 | }
65 |
66 | if (!Pattern.matches("[" + DIGITS + "]*", string)) {
67 | throwIllegalArgumentException("String '%s' contains illegal characters, only '%s' are allowed", string, DIGITS);
68 | }
69 |
70 | return IntStream.range(0, string.length())
71 | .mapToObj(index -> BigInteger.valueOf(charAt.apply(string, index)).multiply(BASE.pow(index)))
72 | .reduce(BigInteger.ZERO, (acc, value) -> {
73 | BigInteger sum = acc.add(value);
74 | if (bitLimit > 0 && sum.bitLength() > bitLimit) {
75 | throwIllegalArgumentException("String '%s' contains more than 128bit information", string);
76 | }
77 | return sum;
78 | });
79 |
80 | }
81 |
82 | private static BiFunction