Clover icon

sunshower-base

  1. Project Clover database Fri Apr 6 2018 03:41:27 UTC
  2. Package io.sunshower.encodings

File Base58.java

 

Coverage histogram

../../../img/srcFileCovDistChart7.png
25% of files have more coverage

Code metrics

52
93
12
2
214
166
45
0.48
7.75
6
3.75

Classes

Class Line # Actions
Base58 8 91 43
0.6209150662.1%
Base58.Alphabets 13 2 2
0.550%
 

Contributing tests

This file is covered by 21 tests. .

Source view

1    package io.sunshower.encodings;
2   
3    import java.io.IOException;
4    import java.io.OutputStream;
5    import java.util.Arrays;
6    import java.util.BitSet;
7   
 
8    public class Base58 implements Encoding {
9   
10    private final char zero;
11    private final char[] alphabet;
12   
 
13    public enum Alphabets {
14    Default("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"),
15    Ripple("rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"),
16    Flickr("123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ");
17   
18    final char[] data;
19   
 
20  3 toggle Alphabets(String input) {
21  3 this.data = input.toCharArray();
22    }
23   
 
24  0 toggle public char[] getAlphabet() {
25  0 return Arrays.copyOf(data, data.length);
26    }
27    }
28   
29    final int[] indexes;
30   
 
31  11 toggle private Base58(Alphabets alphabet) {
32  11 this(alphabet.data);
33    }
34   
 
35  11 toggle private Base58(char[] alphabet) {
36  11 this.alphabet = alphabet;
37  11 this.zero = alphabet[0];
38  11 indexes = new int[128];
39  11 Arrays.fill(indexes, -1);
40  649 for (int i = 0; i < alphabet.length; i++) {
41  638 indexes[alphabet[i]] = i;
42    }
43    }
44   
 
45  0 toggle @Override
46    public boolean test(byte[] input) {
47  0 final BitSet fst = new BitSet();
48  0 for (char b : alphabet) {
49  0 fst.set(b);
50    }
51   
52  0 for (byte b : input) {
53  0 if (!fst.get(b)) {
54  0 return false;
55    }
56    }
57  0 return true;
58    }
59   
 
60  200003 toggle @Override
61    public boolean test(String input) {
62   
63  200003 final BitSet fst = new BitSet();
64  200003 for (char b : alphabet) {
65  11600174 fst.set(b);
66    }
67   
68  4397281 for (int i = 0; i < input.length(); i++) {
69  4197278 if (!fst.get(input.charAt(i))) {
70  0 return false;
71    }
72    }
73  200003 return true;
74    }
75   
 
76  0 toggle @Override
77    public void encode(byte[] input, OutputStream os) throws IOException {
78  0 int length = input.length;
79  0 int zeros = 0, i, j, carry;
80  0 while (zeros < length && input[zeros] == 0) {
81  0 zeros++;
82    }
83   
84  0 int size = (length - zeros) * 138 / 100 + 1;
85   
86  0 byte[] result = new byte[size];
87   
88  0 int max = size - 1;
89   
90  0 for (i = zeros; i < length; i++) {
91  0 j = size - 1;
92  0 for (carry = input[i]; j > max || carry != 0; j--) {
93  0 carry = carry + 256 * input[j];
94  0 result[j] = (byte) (carry % 58);
95  0 carry /= 58;
96    }
97  0 max = j;
98    }
99   
100  0 for (j = 0; j < size && result[j] == 0; j++) ;
101   
102  0 if (zeros != 0) {
103  0 for (i = 0; i < zeros; i++) {
104  0 os.write(zero);
105    }
106    }
107   
108  0 for (i = zeros; j < size; i++) {
109  0 os.write(alphabet[result[j++]]);
110    }
111    }
112   
 
113  300116 toggle @Override
114    public String encode(byte[] in) {
115   
116  300116 byte[] input = Arrays.copyOf(in, in.length);
117   
118  300116 int length = input.length;
119   
120  300116 if (length == 0) {
121  0 return "";
122    }
123   
124  300116 int zeros = 0;
125  700544 while (zeros < length && input[zeros] == 0) {
126  400428 zeros++;
127    }
128   
129  300116 final char[] encoded = new char[input.length * 2];
130   
131  300116 int output = encoded.length;
132   
133  6102114 for (int start = zeros; start < length; ) {
134  5801998 encoded[--output] = alphabet[mod(input, start, 256, 58)];
135  5801998 if (input[start] == 0) {
136  4403414 ++start;
137    }
138    }
139   
140  300116 while (output < encoded.length && encoded[output] == 0) {
141  0 ++output;
142    }
143   
144  700544 while (--zeros >= 0) {
145  400428 encoded[--output] = zero;
146    }
147   
148  300116 return new String(encoded, output, encoded.length - output);
149    }
150   
 
151  500116 toggle @Override
152    public byte[] decode(String input) {
153  500116 int length = input.length();
154  500116 if (length == 0) {
155  0 return new byte[0];
156    }
157   
158  500116 byte[] bytes = new byte[length];
159   
160  10899793 for (int i = 0; i < length; i++) {
161  10399677 char ch = input.charAt(i);
162  10399677 int digit = ch < 128 ? indexes[ch] : -1;
163   
164  10399677 if (digit < 0) {
165  0 throw new IllegalArgumentException(
166    String.format("Unexpected character '%c' at index %d", ch, i));
167    }
168   
169  10399677 bytes[i] = (byte) digit;
170    }
171   
172  500116 int zeros = 0;
173  1100948 while (zeros < length && bytes[zeros] == 0) {
174  600832 ++zeros;
175    }
176   
177  500116 byte[] decoded = new byte[length];
178   
179  500116 int start = length;
180   
181  10298961 for (int istart = zeros; istart < length; ) {
182  9798845 decoded[--start] = mod(bytes, istart, 58, 256);
183  9798845 if (bytes[istart] == 0) {
184  9798845 ++istart;
185    }
186    }
187   
188  2895929 while (start < length && decoded[start] == 0) {
189  2395813 ++start;
190    }
191   
192  500116 return Arrays.copyOfRange(decoded, start - zeros, length);
193    }
194   
 
195  100 toggle @Override
196    public String encode(String input) {
197  100 return encode(input.getBytes());
198    }
199   
 
200  15600843 toggle static byte mod(byte[] d, int fst, int base, int divisor) {
201  15600843 int rem = 0;
202  163168648 for (int i = fst; i < d.length; i++) {
203  147567805 int digit = (int) d[i] & 0xFF;
204  147567805 int t = rem * base + digit;
205  147567805 d[i] = (byte) (t / divisor);
206  147567805 rem = t % divisor;
207    }
208  15600843 return (byte) rem;
209    }
210   
 
211  11 toggle public static Encoding getInstance(Alphabets alphabet) {
212  11 return new Base58(alphabet);
213    }
214    }