1 | package drjava.util; |
2 | |
3 | /** |
4 | * Static methods for translating Base64 encoded strings to byte arrays |
5 | * and vice-versa. |
6 | * Copied from java.util.prefs.Base64 |
7 | * |
8 | * @author Josh Bloch |
9 | * @see java.util.prefs.Preferences |
10 | * @since 1.4 |
11 | */ |
12 | public class Base64 { |
13 | /** |
14 | * Translates the specified byte array into a Base64 string as per |
15 | * Preferences.put(byte[]). |
16 | */ |
17 | public static String byteArrayToBase64(byte[] a) { |
18 | return byteArrayToBase64(a, false); |
19 | } |
20 | |
21 | /** |
22 | * Translates the specified byte array into an "alternate representation" |
23 | * Base64 string. This non-standard variant uses an alphabet that does |
24 | * not contain the uppercase alphabetic characters, which makes it |
25 | * suitable for use in situations where case-folding occurs. |
26 | */ |
27 | public static String byteArrayToAltBase64(byte[] a) { |
28 | return byteArrayToBase64(a, true); |
29 | } |
30 | |
31 | private static String byteArrayToBase64(byte[] a, boolean alternate) { |
32 | int aLen = a.length; |
33 | int numFullGroups = aLen/3; |
34 | int numBytesInPartialGroup = aLen - 3*numFullGroups; |
35 | int resultLen = 4*((aLen + 2)/3); |
36 | StringBuffer result = new StringBuffer(resultLen); |
37 | char[] intToAlpha = (alternate ? intToAltBase64 : intToBase64); |
38 | |
39 | // Translate all full groups from byte array elements to Base64 |
40 | int inCursor = 0; |
41 | for (int i=0; i<numFullGroups; i++) { |
42 | int byte0 = a[inCursor++] & 0xff; |
43 | int byte1 = a[inCursor++] & 0xff; |
44 | int byte2 = a[inCursor++] & 0xff; |
45 | result.append(intToAlpha[byte0 >> 2]); |
46 | result.append(intToAlpha[(byte0 << 4)&0x3f | (byte1 >> 4)]); |
47 | result.append(intToAlpha[(byte1 << 2)&0x3f | (byte2 >> 6)]); |
48 | result.append(intToAlpha[byte2 & 0x3f]); |
49 | } |
50 | |
51 | // Translate partial group if present |
52 | if (numBytesInPartialGroup != 0) { |
53 | int byte0 = a[inCursor++] & 0xff; |
54 | result.append(intToAlpha[byte0 >> 2]); |
55 | if (numBytesInPartialGroup == 1) { |
56 | result.append(intToAlpha[(byte0 << 4) & 0x3f]); |
57 | result.append("=="); |
58 | } else { |
59 | // assert numBytesInPartialGroup == 2; |
60 | int byte1 = a[inCursor++] & 0xff; |
61 | result.append(intToAlpha[(byte0 << 4)&0x3f | (byte1 >> 4)]); |
62 | result.append(intToAlpha[(byte1 << 2)&0x3f]); |
63 | result.append('='); |
64 | } |
65 | } |
66 | // assert inCursor == a.length; |
67 | // assert result.length() == resultLen; |
68 | return result.toString(); |
69 | } |
70 | |
71 | /** |
72 | * This array is a lookup table that translates 6-bit positive integer |
73 | * index values into their "Base64 Alphabet" equivalents as specified |
74 | * in Table 1 of RFC 2045. |
75 | */ |
76 | private static final char intToBase64[] = { |
77 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', |
78 | 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', |
79 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', |
80 | 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', |
81 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' |
82 | }; |
83 | |
84 | /** |
85 | * This array is a lookup table that translates 6-bit positive integer |
86 | * index values into their "Alternate Base64 Alphabet" equivalents. |
87 | * This is NOT the real Base64 Alphabet as per in Table 1 of RFC 2045. |
88 | * This alternate alphabet does not use the capital letters. It is |
89 | * designed for use in environments where "case folding" occurs. |
90 | */ |
91 | private static final char intToAltBase64[] = { |
92 | '!', '"', '#', '$', '%', '&', '\'', '(', ')', ',', '-', '.', ':', |
93 | ';', '<', '>', '@', '[', ']', '^', '`', '_', '{', '|', '}', '~', |
94 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', |
95 | 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', |
96 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '?' |
97 | }; |
98 | |
99 | /** |
100 | * Translates the specified Base64 string (as per Preferences.get(byte[])) |
101 | * into a byte array. |
102 | * |
103 | * @throw IllegalArgumentException if <tt>s</tt> is not a valid Base64 |
104 | * string. |
105 | */ |
106 | public static byte[] base64ToByteArray(String s) { |
107 | return base64ToByteArray(s, false); |
108 | } |
109 | |
110 | /** |
111 | * Translates the specified "alternate representation" Base64 string |
112 | * into a byte array. |
113 | * |
114 | * @throw IllegalArgumentException or ArrayOutOfBoundsException |
115 | * if <tt>s</tt> is not a valid alternate representation |
116 | * Base64 string. |
117 | */ |
118 | public static byte[] altBase64ToByteArray(String s) { |
119 | return base64ToByteArray(s, true); |
120 | } |
121 | |
122 | private static byte[] base64ToByteArray(String s, boolean alternate) { |
123 | byte[] alphaToInt = (alternate ? altBase64ToInt : base64ToInt); |
124 | int sLen = s.length(); |
125 | int numGroups = sLen/4; |
126 | if (4*numGroups != sLen) |
127 | throw new IllegalArgumentException( |
128 | "String length must be a multiple of four."); |
129 | int missingBytesInLastGroup = 0; |
130 | int numFullGroups = numGroups; |
131 | if (sLen != 0) { |
132 | if (s.charAt(sLen-1) == '=') { |
133 | missingBytesInLastGroup++; |
134 | numFullGroups--; |
135 | } |
136 | if (s.charAt(sLen-2) == '=') |
137 | missingBytesInLastGroup++; |
138 | } |
139 | byte[] result = new byte[3*numGroups - missingBytesInLastGroup]; |
140 | |
141 | // Translate all full groups from base64 to byte array elements |
142 | int inCursor = 0, outCursor = 0; |
143 | for (int i=0; i<numFullGroups; i++) { |
144 | int ch0 = base64toInt(s.charAt(inCursor++), alphaToInt); |
145 | int ch1 = base64toInt(s.charAt(inCursor++), alphaToInt); |
146 | int ch2 = base64toInt(s.charAt(inCursor++), alphaToInt); |
147 | int ch3 = base64toInt(s.charAt(inCursor++), alphaToInt); |
148 | result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4)); |
149 | result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2)); |
150 | result[outCursor++] = (byte) ((ch2 << 6) | ch3); |
151 | } |
152 | |
153 | // Translate partial group, if present |
154 | if (missingBytesInLastGroup != 0) { |
155 | int ch0 = base64toInt(s.charAt(inCursor++), alphaToInt); |
156 | int ch1 = base64toInt(s.charAt(inCursor++), alphaToInt); |
157 | result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4)); |
158 | |
159 | if (missingBytesInLastGroup == 1) { |
160 | int ch2 = base64toInt(s.charAt(inCursor++), alphaToInt); |
161 | result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2)); |
162 | } |
163 | } |
164 | // assert inCursor == s.length()-missingBytesInLastGroup; |
165 | // assert outCursor == result.length; |
166 | return result; |
167 | } |
168 | |
169 | /** |
170 | * Translates the specified character, which is assumed to be in the |
171 | * "Base 64 Alphabet" into its equivalent 6-bit positive integer. |
172 | * |
173 | * @throw IllegalArgumentException or ArrayOutOfBoundsException if |
174 | * c is not in the Base64 Alphabet. |
175 | */ |
176 | private static int base64toInt(char c, byte[] alphaToInt) { |
177 | int result = alphaToInt[c]; |
178 | if (result < 0) |
179 | throw new IllegalArgumentException("Illegal character " + c); |
180 | return result; |
181 | } |
182 | |
183 | /** |
184 | * This array is a lookup table that translates unicode characters |
185 | * drawn from the "Base64 Alphabet" (as specified in Table 1 of RFC 2045) |
186 | * into their 6-bit positive integer equivalents. Characters that |
187 | * are not in the Base64 alphabet but fall within the bounds of the |
188 | * array are translated to -1. |
189 | */ |
190 | private static final byte base64ToInt[] = { |
191 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
192 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
193 | -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, |
194 | 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, |
195 | 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, |
196 | 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, |
197 | 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 |
198 | }; |
199 | |
200 | /** |
201 | * This array is the analogue of base64ToInt, but for the nonstandard |
202 | * variant that avoids the use of uppercase alphabetic characters. |
203 | */ |
204 | private static final byte altBase64ToInt[] = { |
205 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
206 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, |
207 | 2, 3, 4, 5, 6, 7, 8, -1, 62, 9, 10, 11, -1 , 52, 53, 54, 55, 56, 57, |
208 | 58, 59, 60, 61, 12, 13, 14, -1, 15, 63, 16, -1, -1, -1, -1, -1, -1, |
209 | -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, |
210 | -1, -1, -1, 17, -1, 18, 19, 21, 20, 26, 27, 28, 29, 30, 31, 32, 33, |
211 | 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, |
212 | 51, 22, 23, 24, 25 |
213 | }; |
214 | |
215 | public static void main(String args[]) { |
216 | int numRuns = Integer.parseInt(args[0]); |
217 | int numBytes = Integer.parseInt(args[1]); |
218 | java.util.Random rnd = new java.util.Random(); |
219 | for (int i=0; i<numRuns; i++) { |
220 | for (int j=0; j<numBytes; j++) { |
221 | byte[] arr = new byte[j]; |
222 | for (int k=0; k<j; k++) |
223 | arr[k] = (byte)rnd.nextInt(); |
224 | |
225 | String s = byteArrayToBase64(arr); |
226 | byte [] b = base64ToByteArray(s); |
227 | if (!java.util.Arrays.equals(arr, b)) |
228 | System.out.println("Dismal failure!"); |
229 | |
230 | s = byteArrayToAltBase64(arr); |
231 | b = altBase64ToByteArray(s); |
232 | if (!java.util.Arrays.equals(arr, b)) |
233 | System.out.println("Alternate dismal failure!"); |
234 | } |
235 | } |
236 | } |
237 | } |
Snippet is not live.
Travelled to 12 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #3000023 |
Snippet name: | Contents of /home/stefan/ma/src/drjava/util/Base64.java on teubizvjbppd |
Eternal ID of this version: | #3000023/1 |
Text MD5: | 580ad3325fe6e2015d0ba38cd4b8c812 |
Author: | someone |
Category: | |
Type: | New Tinybrain snippet |
Gummipassword: | textfile-loader |
Uploaded from IP: | 46.114.0.222 |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2015-08-24 21:22:06 |
Source code size: | 9086 bytes / 237 lines |
Pitched / IR pitched: | No / Yes |
Views / Downloads: | 498 / 119 |
Referenced in: | [show references] |