View Javadoc

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       * set up the decoding table.
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           * process the tail end.
93           */
94          int    b1, b2, b3;
95          int    d1, d2;
96  
97          switch (modulus)
98          {
99          case 0:        /* nothing left to do */
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 }