KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > armedbear > j > mail > Base64Decoder


1 /*
2  * Base64Decoder.java
3  *
4  * Copyright (C) 2000-2002 Peter Graves
5  * $Id: Base64Decoder.java,v 1.1.1.1 2002/09/24 16:09:56 piso Exp $
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */

21
22 package org.armedbear.j.mail;
23
24 import java.io.ByteArrayOutputStream JavaDoc;
25 import java.io.IOException JavaDoc;
26 import java.io.OutputStream JavaDoc;
27 import org.armedbear.j.Debug;
28 import org.armedbear.j.FastStringReader;
29 import org.armedbear.j.Log;
30 import org.armedbear.j.Utilities;
31
32 public final class Base64Decoder
33 {
34     private final static int BAD = 127;
35     private final static int END = -1;
36
37     public static boolean decode(String JavaDoc input, OutputStream JavaDoc outputStream)
38         throws IOException JavaDoc
39     {
40         FastStringReader reader = new FastStringReader(input);
41         String JavaDoc extra = null;
42         String JavaDoc s;
43         while ((s = reader.readLine()) != null) {
44             s = s.trim();
45             if (extra != null) {
46                 s = extra.concat(s);
47                 extra = null;
48             }
49             int length = s.length();
50             if ((length % 4) != 0) {
51                 length = (length / 4) * 4;
52                 extra = s.substring(length);
53                 s = s.substring(0, length);
54             }
55             for (int i = 0; i < length; i += 4) {
56                 if (i+4 < length) {
57                     // Full 4-character block.
58
if (!decode(s, i, outputStream))
59                         return false;
60                 } else {
61                     // Last block (may be short).
62
if (!decodeFinal(s, i, outputStream))
63                         return false;
64                 }
65             }
66         }
67         if (extra != null)
68             return decodeFinal(extra, 0, outputStream);
69         return true;
70     }
71
72     public static byte[] decode(String JavaDoc s)
73     {
74         try {
75             ByteArrayOutputStream JavaDoc out = new ByteArrayOutputStream JavaDoc(80);
76             int length = s.length();
77             for (int i = 0; i < length; i += 4) {
78                 if (i+4 < length) {
79                     // Full 4-character block.
80
if (!decode(s, i, out))
81                         return null;
82                 } else {
83                     // Last block (may be short).
84
if (!decodeFinal(s, i, out))
85                         return null;
86                 }
87             }
88             return out.toByteArray();
89         }
90         catch (IOException JavaDoc e) {
91             Log.error(e);
92             return null;
93         }
94     }
95
96     // Decodes a full 4-character block.
97
private static boolean decode(String JavaDoc input, int offset, OutputStream JavaDoc out)
98         throws IOException JavaDoc
99     {
100         // Check for illegal characters.
101
byte byte1 = values[input.charAt(offset)];
102         if (byte1 == BAD) {
103             error(input, offset);
104             return false;
105         }
106         byte byte2 = values[input.charAt(offset+1)];
107         if (byte2 == BAD) {
108             error(input, offset+1);
109             return false;
110         }
111         byte byte3 = values[input.charAt(offset+2)];
112         if (byte3 == BAD) {
113             error(input, offset+2);
114             return false;
115         }
116         byte byte4 = values[input.charAt(offset+3)];
117         if (byte4 == BAD) {
118             error(input, offset+3);
119             return false;
120         }
121         int n = (byte1 << 18) + (byte2 << 12) + (byte3 << 6) + byte4;
122         out.write((byte)(0xff & (n >> 16)));
123         out.write((byte)(0xff & (n >> 8)));
124         out.write((byte)(0xff & n));
125         return true;
126     }
127
128     // At the end, the input string may have fewer than four characters left.
129
// According to RFC2045: "Because it is used only for padding at the end
130
// of the data, the occurrence of any '=' characters may be taken as
131
// evidence that the end of the data has been reached (without truncation
132
// in transit)."
133
private static boolean decodeFinal(String JavaDoc input, int offset,
134         OutputStream JavaDoc out) throws IOException JavaDoc
135     {
136         byte b0 = 0;
137         byte b1 = 0;
138         byte b2 = 0;
139         byte b3 = 0;
140         int numPaddingChars = 0;
141         Debug.assertTrue(offset < input.length());
142         b0 = values[input.charAt(offset)];
143         if (b0 == END)
144             return true; // OK, end of data.
145
if (b0 == BAD) {
146             error(input, offset);
147             return false;
148         }
149         if (offset + 1 >= input.length()) {
150             Log.error("Base64Decoder.decodeFinal premature end of input");
151             error(input, offset + 1);
152             return false;
153         }
154         b1 = values[input.charAt(offset + 1)];
155         if (b1 == END || b1 == BAD) {
156             // END is not legal here, since then we'd only have 6 bits of
157
// output.
158
error(input, offset + 1);
159             return false;
160         }
161         if (offset + 2 < input.length())
162             b2 = values[input.charAt(offset + 2)];
163         else
164             b2 = END;
165         if (b2 == BAD) {
166             error(input, offset + 2);
167             return false;
168         }
169         if (b2 == END) {
170             b2 = 0;
171             numPaddingChars = 2;
172         } else {
173             // No END yet.
174
if (offset + 3 < input.length())
175                 b3 = values[input.charAt(offset + 3)];
176             else
177                 b3 = END;
178             if (b3 == BAD) {
179                 error(input, offset + 3);
180                 return false;
181             }
182             if (b3 == END) {
183                 b3 = 0;
184                 numPaddingChars = 1;
185             }
186         }
187         int n = (b0 << 18) | (b1 << 12) | (b2 << 6) | b3;
188         out.write((byte)(0xff & (n >> 16)));
189         if (numPaddingChars < 2) {
190             out.write((byte)(0xff & (n >> 8)));
191             if (numPaddingChars == 0)
192                 out.write((byte)(0xff & n));
193         }
194         return true;
195     }
196
197     private static void error(String JavaDoc input, int offset)
198     {
199         Log.error("Base64Decoder error at offset " + offset);
200         Log.error("Base64Decoder input = |" + input + "|");
201         Log.error("Base64Decoder " + Utilities.spaces(offset) + '^');
202     }
203
204     private static final byte values[] =
205     {
206         BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, // 0x00-0x07
207
BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, // 0x09-0xff
208
BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, // 0x10-0x17
209
BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, // 0x18-0x1f
210
BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD, // 0x20-0x27 !"#$%&'
211
BAD, BAD, BAD, 62, BAD, BAD, BAD, 63, // 0x28-0x2f ()*+,-./
212
52, 53, 54, 55, 56, 57, 58, 59, // 0x30-0x37 01234567
213
60, 61, BAD, BAD, BAD, END, BAD, BAD, // 0x38-0x40 89:;<=>?
214
BAD, 0, 1, 2, 3, 4, 5, 6, // 0x41-0x47 @ABCDEFG
215
7, 8, 9, 10, 11, 12, 13, 14, // 0x48-0x4f HIJKLMNO
216
15, 16, 17, 18, 19, 20, 21, 22, // 0x50-0x57 PQRSTUVW
217
23, 24, 25, BAD, BAD, BAD, BAD, BAD, // 0x58-0x5f XYZ[\]^_
218
BAD, 26, 27, 28, 29, 30, 31, 32, // 0x60-0x67 `abcdefg
219
33, 34, 35, 36, 37, 38, 39, 40, // 0x68-0x6f hijklmno
220
41, 42, 43, 44, 45, 46, 47, 48, // 0x70-0x77 pqrstuvw
221
49, 50, 51, BAD, BAD, BAD, BAD, BAD, // 0x78-0x7f xyz{|}~
222
BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
223         BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
224         BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
225         BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
226         BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
227         BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
228         BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
229         BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
230         BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
231         BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
232         BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
233         BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
234         BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
235         BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
236         BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD,
237         BAD, BAD, BAD, BAD, BAD, BAD, BAD, BAD
238     };
239 }
240
Popular Tags