1 /**
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one or more
4 * contributor license agreements. See the NOTICE file distributed with
5 * this work for additional information regarding copyright ownership.
6 * The ASF licenses this file to You under the Apache License, Version 2.0
7 * (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19 package org.apache.geronimo.util.encoders;
20
21 import java.io.IOException;
22 import java.io.OutputStream;
23
24 public class Base64Encoder
25 implements Encoder
26 {
27 protected final byte[] encodingTable =
28 {
29 (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
30 (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
31 (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
32 (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
33 (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
34 (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
35 (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
36 (byte)'v',
37 (byte)'w', (byte)'x', (byte)'y', (byte)'z',
38 (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6',
39 (byte)'7', (byte)'8', (byte)'9',
40 (byte)'+', (byte)'/'
41 };
42
43 protected byte padding = (byte)'=';
44
45
46
47
48 protected final byte[] decodingTable = new byte[128];
49
50 protected void initialiseDecodingTable()
51 {
52 for (int i = 0; i < encodingTable.length; i++)
53 {
54 decodingTable[encodingTable[i]] = (byte)i;
55 }
56 }
57
58 public Base64Encoder()
59 {
60 initialiseDecodingTable();
61 }
62
63 /**
64 * encode the input data producing a base 64 output stream.
65 *
66 * @return the number of bytes produced.
67 */
68 public int encode(
69 byte[] data,
70 int off,
71 int length,
72 OutputStream out)
73 throws IOException
74 {
75 int modulus = length % 3;
76 int dataLength = (length - modulus);
77 int a1, a2, a3;
78
79 for (int i = off; i < off + dataLength; i += 3)
80 {
81 a1 = data[i] & 0xff;
82 a2 = data[i + 1] & 0xff;
83 a3 = data[i + 2] & 0xff;
84
85 out.write(encodingTable[(a1 >>> 2) & 0x3f]);
86 out.write(encodingTable[((a1 << 4) | (a2 >>> 4)) & 0x3f]);
87 out.write(encodingTable[((a2 << 2) | (a3 >>> 6)) & 0x3f]);
88 out.write(encodingTable[a3 & 0x3f]);
89 }
90
91
92
93
94 int b1, b2, b3;
95 int d1, d2;
96
97 switch (modulus)
98 {
99 case 0:
100 break;
101 case 1:
102 d1 = data[off + dataLength] & 0xff;
103 b1 = (d1 >>> 2) & 0x3f;
104 b2 = (d1 << 4) & 0x3f;
105
106 out.write(encodingTable[b1]);
107 out.write(encodingTable[b2]);
108 out.write(padding);
109 out.write(padding);
110 break;
111 case 2:
112 d1 = data[off + dataLength] & 0xff;
113 d2 = data[off + dataLength + 1] & 0xff;
114
115 b1 = (d1 >>> 2) & 0x3f;
116 b2 = ((d1 << 4) | (d2 >>> 4)) & 0x3f;
117 b3 = (d2 << 2) & 0x3f;
118
119 out.write(encodingTable[b1]);
120 out.write(encodingTable[b2]);
121 out.write(encodingTable[b3]);
122 out.write(padding);
123 break;
124 }
125
126 return (dataLength / 3) * 4 + ((modulus == 0) ? 0 : 4);
127 }
128
129 private boolean ignore(
130 char c)
131 {
132 return (c == '\n' || c =='\r' || c == '\t' || c == ' ');
133 }
134
135 /**
136 * decode the base 64 encoded byte data writing it to the given output stream,
137 * whitespace characters will be ignored.
138 *
139 * @return the number of bytes produced.
140 */
141 public int decode(
142 byte[] data,
143 int off,
144 int length,
145 OutputStream out)
146 throws IOException
147 {
148 byte[] bytes;
149 byte b1, b2, b3, b4;
150 int outLen = 0;
151
152 int end = off + length;
153
154 while (end > 0)
155 {
156 if (!ignore((char)data[end - 1]))
157 {
158 break;
159 }
160
161 end--;
162 }
163
164 int i = off;
165 int finish = end - 4;
166
167 while (i < finish)
168 {
169 while ((i < finish) && ignore((char)data[i]))
170 {
171 i++;
172 }
173
174 b1 = decodingTable[data[i++]];
175
176 while ((i < finish) && ignore((char)data[i]))
177 {
178 i++;
179 }
180
181 b2 = decodingTable[data[i++]];
182
183 while ((i < finish) && ignore((char)data[i]))
184 {
185 i++;
186 }
187
188 b3 = decodingTable[data[i++]];
189
190 while ((i < finish) && ignore((char)data[i]))
191 {
192 i++;
193 }
194
195 b4 = decodingTable[data[i++]];
196
197 out.write((b1 << 2) | (b2 >> 4));
198 out.write((b2 << 4) | (b3 >> 2));
199 out.write((b3 << 6) | b4);
200
201 outLen += 3;
202 }
203
204 if (data[end - 2] == padding)
205 {
206 b1 = decodingTable[data[end - 4]];
207 b2 = decodingTable[data[end - 3]];
208
209 out.write((b1 << 2) | (b2 >> 4));
210
211 outLen += 1;
212 }
213 else if (data[end - 1] == padding)
214 {
215 b1 = decodingTable[data[end - 4]];
216 b2 = decodingTable[data[end - 3]];
217 b3 = decodingTable[data[end - 2]];
218
219 out.write((b1 << 2) | (b2 >> 4));
220 out.write((b2 << 4) | (b3 >> 2));
221
222 outLen += 2;
223 }
224 else
225 {
226 b1 = decodingTable[data[end - 4]];
227 b2 = decodingTable[data[end - 3]];
228 b3 = decodingTable[data[end - 2]];
229 b4 = decodingTable[data[end - 1]];
230
231 out.write((b1 << 2) | (b2 >> 4));
232 out.write((b2 << 4) | (b3 >> 2));
233 out.write((b3 << 6) | b4);
234
235 outLen += 3;
236 }
237
238 return outLen;
239 }
240
241 /**
242 * decode the base 64 encoded String data writing it to the given output stream,
243 * whitespace characters will be ignored.
244 *
245 * @return the number of bytes produced.
246 */
247 public int decode(
248 String data,
249 OutputStream out)
250 throws IOException
251 {
252 byte[] bytes;
253 byte b1, b2, b3, b4;
254 int length = 0;
255
256 int end = data.length();
257
258 while (end > 0)
259 {
260 if (!ignore(data.charAt(end - 1)))
261 {
262 break;
263 }
264
265 end--;
266 }
267
268 int i = 0;
269 int finish = end - 4;
270
271 while (i < finish)
272 {
273 while ((i < finish) && ignore(data.charAt(i)))
274 {
275 i++;
276 }
277
278 b1 = decodingTable[data.charAt(i++)];
279
280 while ((i < finish) && ignore(data.charAt(i)))
281 {
282 i++;
283 }
284 b2 = decodingTable[data.charAt(i++)];
285
286 while ((i < finish) && ignore(data.charAt(i)))
287 {
288 i++;
289 }
290 b3 = decodingTable[data.charAt(i++)];
291
292 while ((i < finish) && ignore(data.charAt(i)))
293 {
294 i++;
295 }
296 b4 = decodingTable[data.charAt(i++)];
297
298 out.write((b1 << 2) | (b2 >> 4));
299 out.write((b2 << 4) | (b3 >> 2));
300 out.write((b3 << 6) | b4);
301
302 length += 3;
303 }
304
305 if (data.charAt(end - 2) == padding)
306 {
307 b1 = decodingTable[data.charAt(end - 4)];
308 b2 = decodingTable[data.charAt(end - 3)];
309
310 out.write((b1 << 2) | (b2 >> 4));
311
312 length += 1;
313 }
314 else if (data.charAt(end - 1) == padding)
315 {
316 b1 = decodingTable[data.charAt(end - 4)];
317 b2 = decodingTable[data.charAt(end - 3)];
318 b3 = decodingTable[data.charAt(end - 2)];
319
320 out.write((b1 << 2) | (b2 >> 4));
321 out.write((b2 << 4) | (b3 >> 2));
322
323 length += 2;
324 }
325 else
326 {
327 b1 = decodingTable[data.charAt(end - 4)];
328 b2 = decodingTable[data.charAt(end - 3)];
329 b3 = decodingTable[data.charAt(end - 2)];
330 b4 = decodingTable[data.charAt(end - 1)];
331
332 out.write((b1 << 2) | (b2 >> 4));
333 out.write((b2 << 4) | (b3 >> 2));
334 out.write((b3 << 6) | b4);
335
336 length += 3;
337 }
338
339 return length;
340 }
341 }