1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.geronimo.mail.util;
21
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.io.OutputStream;
25 import java.io.PrintStream;
26
27 public class Base64Encoder
28 implements Encoder
29 {
30 protected final byte[] encodingTable =
31 {
32 (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
33 (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
34 (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
35 (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
36 (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
37 (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
38 (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
39 (byte)'v',
40 (byte)'w', (byte)'x', (byte)'y', (byte)'z',
41 (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6',
42 (byte)'7', (byte)'8', (byte)'9',
43 (byte)'+', (byte)'/'
44 };
45
46 protected byte padding = (byte)'=';
47
48
49
50
51 protected final byte[] decodingTable = new byte[256];
52
53 protected void initialiseDecodingTable()
54 {
55 for (int i = 0; i < encodingTable.length; i++)
56 {
57 decodingTable[encodingTable[i]] = (byte)i;
58 }
59 }
60
61 public Base64Encoder()
62 {
63 initialiseDecodingTable();
64 }
65
66
67
68
69
70
71 public int encode(
72 byte[] data,
73 int off,
74 int length,
75 OutputStream out)
76 throws IOException
77 {
78 int modulus = length % 3;
79 int dataLength = (length - modulus);
80 int a1, a2, a3;
81
82 for (int i = off; i < off + dataLength; i += 3)
83 {
84 a1 = data[i] & 0xff;
85 a2 = data[i + 1] & 0xff;
86 a3 = data[i + 2] & 0xff;
87
88 out.write(encodingTable[(a1 >>> 2) & 0x3f]);
89 out.write(encodingTable[((a1 << 4) | (a2 >>> 4)) & 0x3f]);
90 out.write(encodingTable[((a2 << 2) | (a3 >>> 6)) & 0x3f]);
91 out.write(encodingTable[a3 & 0x3f]);
92 }
93
94
95
96
97 int b1, b2, b3;
98 int d1, d2;
99
100 switch (modulus)
101 {
102 case 0:
103 break;
104 case 1:
105 d1 = data[off + dataLength] & 0xff;
106 b1 = (d1 >>> 2) & 0x3f;
107 b2 = (d1 << 4) & 0x3f;
108
109 out.write(encodingTable[b1]);
110 out.write(encodingTable[b2]);
111 out.write(padding);
112 out.write(padding);
113 break;
114 case 2:
115 d1 = data[off + dataLength] & 0xff;
116 d2 = data[off + dataLength + 1] & 0xff;
117
118 b1 = (d1 >>> 2) & 0x3f;
119 b2 = ((d1 << 4) | (d2 >>> 4)) & 0x3f;
120 b3 = (d2 << 2) & 0x3f;
121
122 out.write(encodingTable[b1]);
123 out.write(encodingTable[b2]);
124 out.write(encodingTable[b3]);
125 out.write(padding);
126 break;
127 }
128
129 return (dataLength / 3) * 4 + ((modulus == 0) ? 0 : 4);
130 }
131
132 private boolean ignore(
133 char c)
134 {
135 return (c == '\n' || c =='\r' || c == '\t' || c == ' ');
136 }
137
138
139
140
141
142
143
144 public int decode(
145 byte[] data,
146 int off,
147 int length,
148 OutputStream out)
149 throws IOException
150 {
151 byte[] bytes;
152 byte b1, b2, b3, b4;
153 int outLen = 0;
154
155 int end = off + length;
156
157 while (end > 0)
158 {
159 if (!ignore((char)data[end - 1]))
160 {
161 break;
162 }
163
164 end--;
165 }
166
167 int i = off;
168 int finish = end - 4;
169
170 while (i < finish)
171 {
172 while ((i < finish) && ignore((char)data[i]))
173 {
174 i++;
175 }
176
177 b1 = decodingTable[data[i++]];
178
179 while ((i < finish) && ignore((char)data[i]))
180 {
181 i++;
182 }
183
184 b2 = decodingTable[data[i++]];
185
186 while ((i < finish) && ignore((char)data[i]))
187 {
188 i++;
189 }
190
191 b3 = decodingTable[data[i++]];
192
193 while ((i < finish) && ignore((char)data[i]))
194 {
195 i++;
196 }
197
198 b4 = decodingTable[data[i++]];
199
200 out.write((b1 << 2) | (b2 >> 4));
201 out.write((b2 << 4) | (b3 >> 2));
202 out.write((b3 << 6) | b4);
203
204 outLen += 3;
205 }
206
207 if (data[end - 2] == padding)
208 {
209 b1 = decodingTable[data[end - 4]];
210 b2 = decodingTable[data[end - 3]];
211
212 out.write((b1 << 2) | (b2 >> 4));
213
214 outLen += 1;
215 }
216 else if (data[end - 1] == padding)
217 {
218 b1 = decodingTable[data[end - 4]];
219 b2 = decodingTable[data[end - 3]];
220 b3 = decodingTable[data[end - 2]];
221
222 out.write((b1 << 2) | (b2 >> 4));
223 out.write((b2 << 4) | (b3 >> 2));
224
225 outLen += 2;
226 }
227 else
228 {
229 b1 = decodingTable[data[end - 4]];
230 b2 = decodingTable[data[end - 3]];
231 b3 = decodingTable[data[end - 2]];
232 b4 = decodingTable[data[end - 1]];
233
234 out.write((b1 << 2) | (b2 >> 4));
235 out.write((b2 << 4) | (b3 >> 2));
236 out.write((b3 << 6) | b4);
237
238 outLen += 3;
239 }
240
241 return outLen;
242 }
243
244
245
246
247
248
249
250 public int decode(
251 String data,
252 OutputStream out)
253 throws IOException
254 {
255 byte[] bytes;
256 byte b1, b2, b3, b4;
257 int length = 0;
258
259 int end = data.length();
260
261 while (end > 0)
262 {
263 if (!ignore(data.charAt(end - 1)))
264 {
265 break;
266 }
267
268 end--;
269 }
270
271 int i = 0;
272 int finish = end - 4;
273
274 while (i < finish)
275 {
276 while ((i < finish) && ignore(data.charAt(i)))
277 {
278 i++;
279 }
280
281 b1 = decodingTable[data.charAt(i++)];
282
283 while ((i < finish) && ignore(data.charAt(i)))
284 {
285 i++;
286 }
287 b2 = decodingTable[data.charAt(i++)];
288
289 while ((i < finish) && ignore(data.charAt(i)))
290 {
291 i++;
292 }
293 b3 = decodingTable[data.charAt(i++)];
294
295 while ((i < finish) && ignore(data.charAt(i)))
296 {
297 i++;
298 }
299 b4 = decodingTable[data.charAt(i++)];
300
301 out.write((b1 << 2) | (b2 >> 4));
302 out.write((b2 << 4) | (b3 >> 2));
303 out.write((b3 << 6) | b4);
304
305 length += 3;
306 }
307
308 if (data.charAt(end - 2) == padding)
309 {
310 b1 = decodingTable[data.charAt(end - 4)];
311 b2 = decodingTable[data.charAt(end - 3)];
312
313 out.write((b1 << 2) | (b2 >> 4));
314
315 length += 1;
316 }
317 else if (data.charAt(end - 1) == padding)
318 {
319 b1 = decodingTable[data.charAt(end - 4)];
320 b2 = decodingTable[data.charAt(end - 3)];
321 b3 = decodingTable[data.charAt(end - 2)];
322
323 out.write((b1 << 2) | (b2 >> 4));
324 out.write((b2 << 4) | (b3 >> 2));
325
326 length += 2;
327 }
328 else
329 {
330 b1 = decodingTable[data.charAt(end - 4)];
331 b2 = decodingTable[data.charAt(end - 3)];
332 b3 = decodingTable[data.charAt(end - 2)];
333 b4 = decodingTable[data.charAt(end - 1)];
334
335 out.write((b1 << 2) | (b2 >> 4));
336 out.write((b2 << 4) | (b3 >> 2));
337 out.write((b3 << 6) | b4);
338
339 length += 3;
340 }
341
342 return length;
343 }
344
345
346
347
348
349
350 public int decode(byte[] data, int off, int length, byte[] out) throws IOException
351 {
352 byte[] bytes;
353 byte b1, b2, b3, b4;
354 int outLen = 0;
355
356 int end = off + length;
357
358 while (end > 0)
359 {
360 if (!ignore((char)data[end - 1]))
361 {
362 break;
363 }
364
365 end--;
366 }
367
368 int i = off;
369 int finish = end - 4;
370
371 while (i < finish)
372 {
373 while ((i < finish) && ignore((char)data[i]))
374 {
375 i++;
376 }
377
378 b1 = decodingTable[data[i++]];
379
380 while ((i < finish) && ignore((char)data[i]))
381 {
382 i++;
383 }
384
385 b2 = decodingTable[data[i++]];
386
387 while ((i < finish) && ignore((char)data[i]))
388 {
389 i++;
390 }
391
392 b3 = decodingTable[data[i++]];
393
394 while ((i < finish) && ignore((char)data[i]))
395 {
396 i++;
397 }
398
399 b4 = decodingTable[data[i++]];
400
401 out[outLen++] = (byte)((b1 << 2) | (b2 >> 4));
402 out[outLen++] = (byte)((b2 << 4) | (b3 >> 2));
403 out[outLen++] = (byte)((b3 << 6) | b4);
404 }
405
406 if (data[end - 2] == padding)
407 {
408 b1 = decodingTable[data[end - 4]];
409 b2 = decodingTable[data[end - 3]];
410
411 out[outLen++] = (byte)((b1 << 2) | (b2 >> 4));
412 }
413 else if (data[end - 1] == padding)
414 {
415 b1 = decodingTable[data[end - 4]];
416 b2 = decodingTable[data[end - 3]];
417 b3 = decodingTable[data[end - 2]];
418
419 out[outLen++] = (byte)((b1 << 2) | (b2 >> 4));
420 out[outLen++] = (byte)((b2 << 4) | (b3 >> 2));
421 }
422 else
423 {
424 b1 = decodingTable[data[end - 4]];
425 b2 = decodingTable[data[end - 3]];
426 b3 = decodingTable[data[end - 2]];
427 b4 = decodingTable[data[end - 1]];
428
429 out[outLen++] = (byte)((b1 << 2) | (b2 >> 4));
430 out[outLen++] = (byte)((b2 << 4) | (b3 >> 2));
431 out[outLen++] = (byte)((b3 << 6) | b4);
432 }
433
434 return outLen;
435 }
436
437
438
439
440
441
442
443
444
445 public boolean isValidBase64(int ch) {
446
447 return ch == padding || ch == 'A' || decodingTable[ch] != 0;
448 }
449
450
451
452
453
454
455
456
457
458
459
460
461
462 public void encodeWord(InputStream in, String charset, OutputStream out, boolean fold) throws IOException
463 {
464 PrintStream writer = new PrintStream(out);
465
466
467 int limit = 75 - 7 - charset.length();
468 boolean firstLine = true;
469 StringBuffer encodedString = new StringBuffer(76);
470
471 while (true) {
472
473 encode(in, encodedString, limit);
474
475 if (encodedString.length() == 0) {
476 break;
477 }
478
479
480
481 if (!firstLine) {
482 if (fold) {
483 writer.print("\r\n");
484 }
485 else {
486 writer.print(" ");
487 }
488 }
489
490
491 writer.print("=?");
492 writer.print(charset);
493 writer.print("?B?");
494
495 writer.print(encodedString.toString());
496
497 writer.print("?=");
498 writer.flush();
499
500
501 encodedString.setLength(0);
502
503 firstLine = false;
504 }
505 }
506
507
508
509
510
511
512
513
514
515
516
517
518
519 public void encodeWord(byte[] data, StringBuffer out, String charset) throws IOException
520 {
521
522 out.append("=?");
523 out.append(charset);
524 out.append("?B?");
525
526 encodeWordData(data, out);
527
528 out.append("?=");
529 }
530
531
532
533
534
535
536 public void encodeWordData(byte[] data, StringBuffer out)
537 {
538 int modulus = data.length % 3;
539 int dataLength = (data.length - modulus);
540 int a1, a2, a3;
541
542 for (int i = 0; i < dataLength; i += 3)
543 {
544 a1 = data[i] & 0xff;
545 a2 = data[i + 1] & 0xff;
546 a3 = data[i + 2] & 0xff;
547
548 out.append((char)encodingTable[(a1 >>> 2) & 0x3f]);
549 out.append((char)encodingTable[((a1 << 4) | (a2 >>> 4)) & 0x3f]);
550 out.append((char)encodingTable[((a2 << 2) | (a3 >>> 6)) & 0x3f]);
551 out.append((char)encodingTable[a3 & 0x3f]);
552 }
553
554
555
556
557 int b1, b2, b3;
558 int d1, d2;
559
560 switch (modulus)
561 {
562 case 0:
563 break;
564 case 1:
565 d1 = data[dataLength] & 0xff;
566 b1 = (d1 >>> 2) & 0x3f;
567 b2 = (d1 << 4) & 0x3f;
568
569 out.append((char)encodingTable[b1]);
570 out.append((char)encodingTable[b2]);
571 out.append((char)padding);
572 out.append((char)padding);
573 break;
574 case 2:
575 d1 = data[dataLength] & 0xff;
576 d2 = data[dataLength + 1] & 0xff;
577
578 b1 = (d1 >>> 2) & 0x3f;
579 b2 = ((d1 << 4) | (d2 >>> 4)) & 0x3f;
580 b3 = (d2 << 2) & 0x3f;
581
582 out.append((char)encodingTable[b1]);
583 out.append((char)encodingTable[b2]);
584 out.append((char)encodingTable[b3]);
585 out.append((char)padding);
586 break;
587 }
588 }
589
590
591
592
593
594
595
596 public void encode(InputStream in, StringBuffer out, int limit) throws IOException
597 {
598 int count = limit / 4;
599 byte [] inBuffer = new byte[3];
600
601 while (count-- > 0) {
602
603 int readCount = in.read(inBuffer);
604
605 if (readCount == 3) {
606 int a1 = inBuffer[0] & 0xff;
607 int a2 = inBuffer[1] & 0xff;
608 int a3 = inBuffer[2] & 0xff;
609
610 out.append((char)encodingTable[(a1 >>> 2) & 0x3f]);
611 out.append((char)encodingTable[((a1 << 4) | (a2 >>> 4)) & 0x3f]);
612 out.append((char)encodingTable[((a2 << 2) | (a3 >>> 6)) & 0x3f]);
613 out.append((char)encodingTable[a3 & 0x3f]);
614
615 }
616 else if (readCount <= 0) {
617
618 return;
619 }
620 else if (readCount == 1) {
621 int a1 = inBuffer[0] & 0xff;
622 out.append((char)encodingTable[(a1 >>> 2) & 0x3f]);
623 out.append((char)encodingTable[(a1 << 4) & 0x3f]);
624 out.append((char)padding);
625 out.append((char)padding);
626 return;
627 }
628 else if (readCount == 2) {
629 int a1 = inBuffer[0] & 0xff;
630 int a2 = inBuffer[1] & 0xff;
631
632 out.append((char)encodingTable[(a1 >>> 2) & 0x3f]);
633 out.append((char)encodingTable[((a1 << 4) | (a2 >>> 4)) & 0x3f]);
634 out.append((char)encodingTable[(a2 << 2) & 0x3f]);
635 out.append((char)padding);
636 return;
637 }
638 }
639 }
640
641
642
643
644
645
646
647
648
649
650
651
652
653 public int estimateEncodedLength(byte[] data)
654 {
655 return ((data.length + 2) / 3) * 4;
656 }
657 }