1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.sw4j.tool.barcode.random.coder;
18
19 import java.util.Arrays;
20
21
22
23
24
25
26
27
28
29
30 public final class Base58 {
31
32
33
34
35
36
37 private static final int NUMBER_ASCII_CHARS = 128;
38
39
40
41
42
43
44 private static final int BYTE_BASE = 256;
45
46
47
48
49
50
51 private static final int BASE = 58;
52
53
54
55
56
57
58 private static final int BYTE_MASK = 0xff;
59
60
61
62
63
64
65 private static final char[] ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
66
67
68
69
70
71
72 private static final int[] INDEX = new int[NUMBER_ASCII_CHARS];
73
74
75
76
77
78
79 static {
80 for (int i = 0; i < INDEX.length; i++) {
81 INDEX[i] = -1;
82 }
83 for (int i = 0; i < ALPHABET.length; i++) {
84 INDEX[ALPHABET[i]] = i;
85 }
86 }
87
88
89
90
91
92
93 private Base58() {
94 }
95
96
97
98
99
100
101
102
103 public static String encode(final byte[] data) {
104 StringBuilder result = new StringBuilder();
105 byte[] copy = Arrays.copyOf(data, data.length);
106 int leadingZeros = leadingZeros(data);
107 boolean done = (copy.length == 0 || copy.length == leadingZeros);
108 while (!done) {
109 byte remainder = divide(copy, BYTE_BASE, BASE);
110 result.insert(0, ALPHABET[remainder]);
111 done = true;
112 for (int i = 0; i < copy.length; i++) {
113 done = done & (copy[i] == 0);
114 }
115 }
116 for (int i = 0; i < leadingZeros; i++) {
117 result.insert(0, ALPHABET[0]);
118 }
119 return result.toString();
120 }
121
122
123
124
125
126
127
128
129 private static int leadingZeros(final byte[] data) {
130 int leadingZeros = 0;
131 boolean foundNonZero = false;
132 for (int i = 0; !foundNonZero && i < data.length; i++) {
133 if (data[i] == 0) {
134 leadingZeros++;
135 } else {
136 foundNonZero = true;
137 }
138 }
139 return leadingZeros;
140 }
141
142
143
144
145
146
147
148
149 public static byte[] decode(final String data) {
150 byte[] input = new byte[data.length()];
151 byte[] output = new byte[data.length()];
152 for (int i = 0; i < data.length(); i++) {
153 char c = data.charAt(i);
154 int digit = c < NUMBER_ASCII_CHARS ? INDEX[c] : -1;
155 if (digit < 0) {
156 throw new IllegalArgumentException(String.format("The digit '%c' is not recognized.", c));
157 }
158 input[i] = (byte)digit;
159 }
160 int leadingZeros = leadingZeros(input);
161 int outputIndex = output.length;
162 int zeros = leadingZeros(input);
163 while (zeros < input.length) {
164 byte remainder = divide(input, BASE, BYTE_BASE);
165 output[--outputIndex] = remainder;
166 zeros = leadingZeros(input);
167 }
168 return Arrays.copyOfRange(output, outputIndex - leadingZeros, output.length);
169 }
170
171
172
173
174
175
176
177
178
179
180
181 public static byte divide(final byte[] dividend, final int base, final int divisor) {
182 if (divisor == 0) {
183 throw new IllegalArgumentException("The divisor may not be 0.");
184 }
185 int remainder = 0;
186 for (int i = 0; i < dividend.length; i++) {
187 int digit = (int)(dividend[i] & BYTE_MASK);
188 if (digit > base) {
189 throw new IllegalArgumentException(
190 String.format("The digit at place %d (%d) is larger than the base %d.", i, digit, base));
191 }
192 int temp = remainder * base + digit;
193 dividend[i] = (byte)(temp / divisor);
194 remainder = temp % divisor;
195 }
196 return (byte)remainder;
197 }
198
199 }