KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > cjdbc > common > stream > encoding > Base64


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 1999-2002 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Xerces" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation and was
52  * originally based on software copyright (c) 1999, International
53  * Business Machines, Inc., http://www.apache.org. For more
54  * information on the Apache Software Foundation, please see
55  * <http://www.apache.org/>.
56  */

57
58 package org.objectweb.cjdbc.common.stream.encoding;
59
60 /**
61  * This class provides encode/decode for RFC 2045 Base64 as defined by RFC 2045,
62  * N. Freed and N. Borenstein. RFC 2045: Multipurpose Internet Mail Extensions
63  * (MIME) Part One: Format of Internet Message Bodies. Reference 1996 Available
64  * at: http://www.ietf.org/rfc/rfc2045.txt This class is used by XML Schema
65  * binary format validation This implementation does not encode/decode streaming
66  * data. You need the data that you will encode/decode already on a byte arrray.
67  *
68  * @author Jeffrey Rodriguez
69  * @author Sandy Gao
70  * @version $Id: Base64.java,v 1.4 2005/06/18 02:47:39 cecchet Exp $
71  */

72 public final class Base64
73 {
74   private static final int BASELENGTH = 255;
75   private static final int LOOKUPLENGTH = 64;
76   private static final int TWENTYFOURBITGROUP = 24;
77   private static final int EIGHTBIT = 8;
78   private static final int SIXTEENBIT = 16;
79   private static final int FOURBYTE = 4;
80   private static final int SIGN = -128;
81   private static final char PAD = '=';
82   private static final boolean F_DEBUG = false;
83   private static final byte[] BASE64_ALPHABET = new byte[BASELENGTH];
84   private static final char[] LOOKUP_BASE64_ALPHABET = new char[LOOKUPLENGTH];
85
86   static
87   {
88
89     for (int i = 0; i < BASELENGTH; i++)
90     {
91       BASE64_ALPHABET[i] = -1;
92     }
93     for (int i = 'Z'; i >= 'A'; i--)
94     {
95       BASE64_ALPHABET[i] = (byte) (i - 'A');
96     }
97     for (int i = 'z'; i >= 'a'; i--)
98     {
99       BASE64_ALPHABET[i] = (byte) (i - 'a' + 26);
100     }
101
102     for (int i = '9'; i >= '0'; i--)
103     {
104       BASE64_ALPHABET[i] = (byte) (i - '0' + 52);
105     }
106
107     BASE64_ALPHABET['+'] = 62;
108     BASE64_ALPHABET['/'] = 63;
109
110     for (int i = 0; i <= 25; i++)
111       LOOKUP_BASE64_ALPHABET[i] = (char) ('A' + i);
112
113     for (int i = 26, j = 0; i <= 51; i++, j++)
114       LOOKUP_BASE64_ALPHABET[i] = (char) ('a' + j);
115
116     for (int i = 52, j = 0; i <= 61; i++, j++)
117       LOOKUP_BASE64_ALPHABET[i] = (char) ('0' + j);
118     LOOKUP_BASE64_ALPHABET[62] = '+';
119     LOOKUP_BASE64_ALPHABET[63] = '/';
120   }
121
122   protected static boolean isWhiteSpace(char octect)
123   {
124     return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
125   }
126
127   protected static boolean isPad(char octect)
128   {
129     return (octect == PAD);
130   }
131
132   protected static boolean isData(char octect)
133   {
134     return (BASE64_ALPHABET[octect] != -1);
135   }
136
137   protected static boolean isBase64(char octect)
138   {
139     return (isWhiteSpace(octect) || isPad(octect) || isData(octect));
140   }
141
142   /**
143    * Encodes hex octects into Base64
144    *
145    * @param binaryData Array containing binaryData
146    * @return Encoded Base64 array
147    */

148   public static String JavaDoc encode(byte[] binaryData)
149   {
150
151     if (binaryData == null)
152       return null;
153
154     int lengthDataBits = binaryData.length * EIGHTBIT;
155     if (lengthDataBits == 0)
156     {
157       return "";
158     }
159
160     int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
161     int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
162     int numberQuartet = fewerThan24bits != 0
163         ? numberTriplets + 1
164         : numberTriplets;
165     int numberLines = (numberQuartet - 1) / 19 + 1;
166     char[] encodedData = null;
167
168     encodedData = new char[numberQuartet * 4 + numberLines];
169
170     byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
171
172     int encodedIndex = 0;
173     int dataIndex = 0;
174     int i = 0;
175     if (F_DEBUG)
176     {
177       System.out.println("number of triplets = " + numberTriplets);
178     }
179
180     for (int line = 0; line < numberLines - 1; line++)
181     {
182       for (int quartet = 0; quartet < 19; quartet++)
183       {
184         b1 = binaryData[dataIndex++];
185         b2 = binaryData[dataIndex++];
186         b3 = binaryData[dataIndex++];
187
188         if (F_DEBUG)
189         {
190           System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3);
191         }
192
193         l = (byte) (b2 & 0x0f);
194         k = (byte) (b1 & 0x03);
195
196         byte val1 = ((b1 & SIGN) == 0)
197             ? (byte) (b1 >> 2)
198             : (byte) ((b1) >> 2 ^ 0xc0);
199
200         byte val2 = ((b2 & SIGN) == 0)
201             ? (byte) (b2 >> 4)
202             : (byte) ((b2) >> 4 ^ 0xf0);
203         byte val3 = ((b3 & SIGN) == 0)
204             ? (byte) (b3 >> 6)
205             : (byte) ((b3) >> 6 ^ 0xfc);
206
207         if (F_DEBUG)
208         {
209           System.out.println("val2 = " + val2);
210           System.out.println("k4 = " + (k << 4));
211           System.out.println("vak = " + (val2 | (k << 4)));
212         }
213
214         encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[val1];
215         encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[val2 | (k << 4)];
216         encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[(l << 2) | val3];
217         encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[b3 & 0x3f];
218
219         i++;
220       }
221       encodedData[encodedIndex++] = 0xa;
222     }
223
224     for (; i < numberTriplets; i++)
225     {
226       b1 = binaryData[dataIndex++];
227       b2 = binaryData[dataIndex++];
228       b3 = binaryData[dataIndex++];
229
230       if (F_DEBUG)
231       {
232         System.out.println("b1= " + b1 + ", b2= " + b2 + ", b3= " + b3);
233       }
234
235       l = (byte) (b2 & 0x0f);
236       k = (byte) (b1 & 0x03);
237
238       byte val1 = ((b1 & SIGN) == 0)
239           ? (byte) (b1 >> 2)
240           : (byte) ((b1) >> 2 ^ 0xc0);
241
242       byte val2 = ((b2 & SIGN) == 0)
243           ? (byte) (b2 >> 4)
244           : (byte) ((b2) >> 4 ^ 0xf0);
245       byte val3 = ((b3 & SIGN) == 0)
246           ? (byte) (b3 >> 6)
247           : (byte) ((b3) >> 6 ^ 0xfc);
248
249       if (F_DEBUG)
250       {
251         System.out.println("val2 = " + val2);
252         System.out.println("k4 = " + (k << 4));
253         System.out.println("vak = " + (val2 | (k << 4)));
254       }
255
256       encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[val1];
257       encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[val2 | (k << 4)];
258       encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[(l << 2) | val3];
259       encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[b3 & 0x3f];
260     }
261
262     // form integral number of 6-bit groups
263
if (fewerThan24bits == EIGHTBIT)
264     {
265       b1 = binaryData[dataIndex];
266       k = (byte) (b1 & 0x03);
267       if (F_DEBUG)
268       {
269         System.out.println("b1=" + b1);
270         System.out.println("b1<<2 = " + (b1 >> 2));
271       }
272       byte val1 = ((b1 & SIGN) == 0)
273           ? (byte) (b1 >> 2)
274           : (byte) ((b1) >> 2 ^ 0xc0);
275       encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[val1];
276       encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[k << 4];
277       encodedData[encodedIndex++] = PAD;
278       encodedData[encodedIndex++] = PAD;
279     }
280     else if (fewerThan24bits == SIXTEENBIT)
281     {
282       b1 = binaryData[dataIndex];
283       b2 = binaryData[dataIndex + 1];
284       l = (byte) (b2 & 0x0f);
285       k = (byte) (b1 & 0x03);
286
287       byte val1 = ((b1 & SIGN) == 0)
288           ? (byte) (b1 >> 2)
289           : (byte) ((b1) >> 2 ^ 0xc0);
290       byte val2 = ((b2 & SIGN) == 0)
291           ? (byte) (b2 >> 4)
292           : (byte) ((b2) >> 4 ^ 0xf0);
293
294       encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[val1];
295       encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[val2 | (k << 4)];
296       encodedData[encodedIndex++] = LOOKUP_BASE64_ALPHABET[l << 2];
297       encodedData[encodedIndex++] = PAD;
298     }
299
300     encodedData[encodedIndex] = 0xa;
301
302     return new String JavaDoc(encodedData);
303   }
304
305   /**
306    * Decodes Base64 data into octects
307    *
308    * @param encoded String encoded in Base64
309    * @return Byte array containing decoded data.
310    */

311   public static byte[] decode(String JavaDoc encoded)
312   {
313
314     if (encoded == null)
315       return null;
316
317     char[] base64Data = encoded.toCharArray();
318     // remove white spaces
319
int len = removeWhiteSpace(base64Data);
320
321     if (len % FOURBYTE != 0)
322     {
323       return null;//should be divisible by four
324
}
325
326     int numberQuadruple = (len / FOURBYTE);
327
328     if (numberQuadruple == 0)
329       return new byte[0];
330
331     byte[] decodedData = null;
332     byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
333     char d1 = 0, d2 = 0, d3 = 0, d4 = 0;
334
335     int i = 0;
336     int encodedIndex = 0;
337     int dataIndex = 0;
338     decodedData = new byte[(numberQuadruple) * 3];
339
340     for (; i < numberQuadruple - 1; i++)
341     {
342       d1 = base64Data[dataIndex++];
343       d2 = base64Data[dataIndex++];
344       d3 = base64Data[dataIndex++];
345       d4 = base64Data[dataIndex++];
346       if (!isData(d1) || !isData(d2) || !isData(d3) || !isData(d4))
347         return null;//if found "no data" just return null
348

349       b1 = BASE64_ALPHABET[d1];
350       b2 = BASE64_ALPHABET[d2];
351       b3 = BASE64_ALPHABET[d3];
352       b4 = BASE64_ALPHABET[d4];
353
354       decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
355       decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
356       decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
357     }
358
359     d1 = base64Data[dataIndex++];
360     d2 = base64Data[dataIndex++];
361     if (!isData(d1) || !isData(d2))
362     {
363       return null;//if found "no data" just return null
364
}
365
366     b1 = BASE64_ALPHABET[d1];
367     b2 = BASE64_ALPHABET[d2];
368
369     d3 = base64Data[dataIndex++];
370     d4 = base64Data[dataIndex++];
371     if (!isData((d3)) || !isData((d4)))
372     {//Check if they are PAD characters
373
if (isPad(d3) && isPad(d4))
374       { //Two PAD e.g. 3c[Pad][Pad]
375
if ((b2 & 0xf) != 0)//last 4 bits should be zero
376
return null;
377         byte[] tmp = new byte[i * 3 + 1];
378         System.arraycopy(decodedData, 0, tmp, 0, i * 3);
379         tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
380         return tmp;
381       }
382       else if (!isPad(d3) && isPad(d4))
383       { //One PAD e.g. 3cQ[Pad]
384
b3 = BASE64_ALPHABET[d3];
385         if ((b3 & 0x3) != 0)//last 2 bits should be zero
386
return null;
387         byte[] tmp = new byte[i * 3 + 2];
388         System.arraycopy(decodedData, 0, tmp, 0, i * 3);
389         tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
390         tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
391         return tmp;
392       }
393       else
394       {
395         return null;//an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X
396
// is non data
397
}
398     }
399     else
400     { //No PAD e.g 3cQl
401
b3 = BASE64_ALPHABET[d3];
402       b4 = BASE64_ALPHABET[d4];
403       decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
404       decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
405       decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
406
407     }
408
409     return decodedData;
410   }
411
412   /**
413    * remove WhiteSpace from MIME containing encoded Base64 data.
414    *
415    * @param data the byte array of base64 data (with WS)
416    * @return the new length
417    */

418   protected static int removeWhiteSpace(char[] data)
419   {
420     if (data == null)
421       return 0;
422
423     // count characters that's not whitespace
424
int newSize = 0;
425     int len = data.length;
426     for (int i = 0; i < len; i++)
427     {
428       if (!isWhiteSpace(data[i]))
429         data[newSize++] = data[i];
430     }
431     return newSize;
432   }
433 }
Popular Tags