1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.util;
21
22 import java.security.InvalidParameterException;
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38 public class Base64 {
39
40
41
42
43
44
45
46
47
48 static final int CHUNK_SIZE = 76;
49
50
51
52
53
54
55 static final byte[] CHUNK_SEPARATOR = "\r\n".getBytes();
56
57
58
59
60 static final int BASELENGTH = 255;
61
62
63
64
65 static final int LOOKUPLENGTH = 64;
66
67
68
69
70 static final int EIGHTBIT = 8;
71
72
73
74
75 static final int SIXTEENBIT = 16;
76
77
78
79
80 static final int TWENTYFOURBITGROUP = 24;
81
82
83
84
85 static final int FOURBYTE = 4;
86
87
88
89
90 static final int SIGN = -128;
91
92
93
94
95 static final byte PAD = (byte) '=';
96
97
98
99 private static byte[] base64Alphabet = new byte[BASELENGTH];
100
101 private static byte[] lookUpBase64Alphabet = new byte[LOOKUPLENGTH];
102
103
104 static {
105 for (int i = 0; i < BASELENGTH; i++) {
106 base64Alphabet[i] = (byte) -1;
107 }
108 for (int i = 'Z'; i >= 'A'; i--) {
109 base64Alphabet[i] = (byte) (i - 'A');
110 }
111 for (int i = 'z'; i >= 'a'; i--) {
112 base64Alphabet[i] = (byte) (i - 'a' + 26);
113 }
114 for (int i = '9'; i >= '0'; i--) {
115 base64Alphabet[i] = (byte) (i - '0' + 52);
116 }
117
118 base64Alphabet['+'] = 62;
119 base64Alphabet['/'] = 63;
120
121 for (int i = 0; i <= 25; i++) {
122 lookUpBase64Alphabet[i] = (byte) ('A' + i);
123 }
124
125 for (int i = 26, j = 0; i <= 51; i++, j++) {
126 lookUpBase64Alphabet[i] = (byte) ('a' + j);
127 }
128
129 for (int i = 52, j = 0; i <= 61; i++, j++) {
130 lookUpBase64Alphabet[i] = (byte) ('0' + j);
131 }
132
133 lookUpBase64Alphabet[62] = (byte) '+';
134 lookUpBase64Alphabet[63] = (byte) '/';
135 }
136
137 private static boolean isBase64(byte octect) {
138 if (octect == PAD) {
139 return true;
140 } else if (base64Alphabet[octect] == -1) {
141 return false;
142 } else {
143 return true;
144 }
145 }
146
147
148
149
150
151
152
153
154
155 public static boolean isArrayByteBase64(byte[] arrayOctect) {
156
157 arrayOctect = discardWhitespace(arrayOctect);
158
159 int length = arrayOctect.length;
160 if (length == 0) {
161
162
163 return true;
164 }
165 for (int i = 0; i < length; i++) {
166 if (!isBase64(arrayOctect[i])) {
167 return false;
168 }
169 }
170 return true;
171 }
172
173
174
175
176
177
178
179
180 public static byte[] encodeBase64(byte[] binaryData) {
181 return encodeBase64(binaryData, false);
182 }
183
184
185
186
187
188
189
190
191 public static byte[] encodeBase64Chunked(byte[] binaryData) {
192 return encodeBase64(binaryData, true);
193 }
194
195
196
197
198
199
200
201
202
203
204
205
206
207 public Object decode(Object pObject) {
208 if (!(pObject instanceof byte[])) {
209 throw new InvalidParameterException(
210 "Parameter supplied to Base64 decode is not a byte[]");
211 }
212 return decode((byte[]) pObject);
213 }
214
215
216
217
218
219
220
221
222 public byte[] decode(byte[] pArray) {
223 return decodeBase64(pArray);
224 }
225
226
227
228
229
230
231
232
233
234
235 public static byte[] encodeBase64(byte[] binaryData, boolean isChunked) {
236 int lengthDataBits = binaryData.length * EIGHTBIT;
237 int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
238 int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
239 byte encodedData[] = null;
240 int encodedDataLength = 0;
241 int nbrChunks = 0;
242
243 if (fewerThan24bits != 0) {
244
245 encodedDataLength = (numberTriplets + 1) * 4;
246 } else {
247
248 encodedDataLength = numberTriplets * 4;
249 }
250
251
252
253
254 if (isChunked) {
255
256 nbrChunks = (CHUNK_SEPARATOR.length == 0 ? 0 : (int) Math
257 .ceil((float) encodedDataLength / CHUNK_SIZE));
258 encodedDataLength += nbrChunks * CHUNK_SEPARATOR.length;
259 }
260
261 encodedData = new byte[encodedDataLength];
262
263 byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
264
265 int encodedIndex = 0;
266 int dataIndex = 0;
267 int i = 0;
268 int nextSeparatorIndex = CHUNK_SIZE;
269 int chunksSoFar = 0;
270
271
272 for (i = 0; i < numberTriplets; i++) {
273 dataIndex = i * 3;
274 b1 = binaryData[dataIndex];
275 b2 = binaryData[dataIndex + 1];
276 b3 = binaryData[dataIndex + 2];
277
278
279
280 l = (byte) (b2 & 0x0f);
281 k = (byte) (b1 & 0x03);
282
283 byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
284 : (byte) ((b1) >> 2 ^ 0xc0);
285 byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
286 : (byte) ((b2) >> 4 ^ 0xf0);
287 byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6)
288 : (byte) ((b3) >> 6 ^ 0xfc);
289
290 encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
291
292
293
294 encodedData[encodedIndex + 1] = lookUpBase64Alphabet[val2
295 | (k << 4)];
296 encodedData[encodedIndex + 2] = lookUpBase64Alphabet[(l << 2)
297 | val3];
298 encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f];
299
300 encodedIndex += 4;
301
302
303 if (isChunked) {
304
305 if (encodedIndex == nextSeparatorIndex) {
306 System.arraycopy(CHUNK_SEPARATOR, 0, encodedData,
307 encodedIndex, CHUNK_SEPARATOR.length);
308 chunksSoFar++;
309 nextSeparatorIndex = (CHUNK_SIZE * (chunksSoFar + 1))
310 + (chunksSoFar * CHUNK_SEPARATOR.length);
311 encodedIndex += CHUNK_SEPARATOR.length;
312 }
313 }
314 }
315
316
317 dataIndex = i * 3;
318
319 if (fewerThan24bits == EIGHTBIT) {
320 b1 = binaryData[dataIndex];
321 k = (byte) (b1 & 0x03);
322
323
324 byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
325 : (byte) ((b1) >> 2 ^ 0xc0);
326 encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
327 encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4];
328 encodedData[encodedIndex + 2] = PAD;
329 encodedData[encodedIndex + 3] = PAD;
330 } else if (fewerThan24bits == SIXTEENBIT) {
331
332 b1 = binaryData[dataIndex];
333 b2 = binaryData[dataIndex + 1];
334 l = (byte) (b2 & 0x0f);
335 k = (byte) (b1 & 0x03);
336
337 byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2)
338 : (byte) ((b1) >> 2 ^ 0xc0);
339 byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4)
340 : (byte) ((b2) >> 4 ^ 0xf0);
341
342 encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
343 encodedData[encodedIndex + 1] = lookUpBase64Alphabet[val2
344 | (k << 4)];
345 encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2];
346 encodedData[encodedIndex + 3] = PAD;
347 }
348
349 if (isChunked) {
350
351 if (chunksSoFar < nbrChunks) {
352 System.arraycopy(CHUNK_SEPARATOR, 0, encodedData,
353 encodedDataLength - CHUNK_SEPARATOR.length,
354 CHUNK_SEPARATOR.length);
355 }
356 }
357
358 return encodedData;
359 }
360
361
362
363
364
365
366
367 public static byte[] decodeBase64(byte[] base64Data) {
368
369 base64Data = discardNonBase64(base64Data);
370
371
372 if (base64Data.length == 0) {
373 return new byte[0];
374 }
375
376 int numberQuadruple = base64Data.length / FOURBYTE;
377 byte decodedData[] = null;
378 byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0;
379
380
381
382 int encodedIndex = 0;
383 int dataIndex = 0;
384 {
385
386 int lastData = base64Data.length;
387
388 while (base64Data[lastData - 1] == PAD) {
389 if (--lastData == 0) {
390 return new byte[0];
391 }
392 }
393 decodedData = new byte[lastData - numberQuadruple];
394 }
395
396 for (int i = 0; i < numberQuadruple; i++) {
397 dataIndex = i * 4;
398 marker0 = base64Data[dataIndex + 2];
399 marker1 = base64Data[dataIndex + 3];
400
401 b1 = base64Alphabet[base64Data[dataIndex]];
402 b2 = base64Alphabet[base64Data[dataIndex + 1]];
403
404 if (marker0 != PAD && marker1 != PAD) {
405
406 b3 = base64Alphabet[marker0];
407 b4 = base64Alphabet[marker1];
408
409 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
410 decodedData[encodedIndex + 1] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
411 decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4);
412 } else if (marker0 == PAD) {
413
414 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
415 } else if (marker1 == PAD) {
416
417 b3 = base64Alphabet[marker0];
418
419 decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
420 decodedData[encodedIndex + 1] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
421 }
422 encodedIndex += 3;
423 }
424 return decodedData;
425 }
426
427
428
429
430
431
432
433
434 static byte[] discardWhitespace(byte[] data) {
435 byte groomedData[] = new byte[data.length];
436 int bytesCopied = 0;
437
438 for (int i = 0; i < data.length; i++) {
439 switch (data[i]) {
440 case (byte) ' ':
441 case (byte) '\n':
442 case (byte) '\r':
443 case (byte) '\t':
444 break;
445 default:
446 groomedData[bytesCopied++] = data[i];
447 }
448 }
449
450 byte packedData[] = new byte[bytesCopied];
451
452 System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
453
454 return packedData;
455 }
456
457
458
459
460
461
462
463
464
465
466 static byte[] discardNonBase64(byte[] data) {
467 byte groomedData[] = new byte[data.length];
468 int bytesCopied = 0;
469
470 for (int i = 0; i < data.length; i++) {
471 if (isBase64(data[i])) {
472 groomedData[bytesCopied++] = data[i];
473 }
474 }
475
476 byte packedData[] = new byte[bytesCopied];
477
478 System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
479
480 return packedData;
481 }
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497 public Object encode(Object pObject) {
498 if (!(pObject instanceof byte[])) {
499 throw new InvalidParameterException(
500 "Parameter supplied to Base64 encode is not a byte[]");
501 }
502 return encode((byte[]) pObject);
503 }
504
505
506
507
508
509
510
511
512 public byte[] encode(byte[] pArray) {
513 return encodeBase64(pArray, false);
514 }
515
516 }