KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > barracuda > plankton > data > Base64


1 package org.enhydra.barracuda.plankton.data;
2
3 /*
4  * ---------------------------------------------------------------------
5  * This class comes from the Apache Xerces library. We have changed the
6  * package name for convenient inclusion in the Barracuda library.
7  * - csc
8  * Addition: updated to version 1.3 (in Xerxes 2.0.0) from 1.1.
9  * Note: There are two versions of Base64.java in Xerces 2.0.0.
10  * - package org.apache.xerces.impl.xs.util; //this one (version 1.3)
11  * - package org.apache.xerces.impl.dv.util; (version 1.2)
12  * The curious thing is that version 1.2 contains the method
13  * "public static String decode(String base64Data)" which version 1.3
14  * does *not* have. Otherwise, the interface is the same (other than
15  * version 1.3 adding some new methods and some better logic). I'm going
16  * to include that method here, since it might be useful. I'm also
17  * adding the corallary method "public static String encode(String stringData)"
18  * to be consistent. Both these methods let the pre-existing encode and
19  * decode methods do the work.
20  * - jrk
21  * ---------------------------------------------------------------------
22  * The Apache Software License, Version 1.1
23  *
24  *
25  * Copyright (c) 1999-2002 The Apache Software Foundation. All rights
26  * reserved.
27  *
28  * Redistribution and use in source and binary forms, with or without
29  * modification, are permitted provided that the following conditions
30  * are met:
31  *
32  * 1. Redistributions of source code must retain the above copyright
33  * notice, this list of conditions and the following disclaimer.
34  *
35  * 2. Redistributions in binary form must reproduce the above copyright
36  * notice, this list of conditions and the following disclaimer in
37  * the documentation and/or other materials provided with the
38  * distribution.
39  *
40  * 3. The end-user documentation included with the redistribution,
41  * if any, must include the following acknowledgment:
42  * "This product includes software developed by the
43  * Apache Software Foundation (http://www.apache.org/)."
44  * Alternately, this acknowledgment may appear in the software itself,
45  * if and wherever such third-party acknowledgments normally appear.
46  *
47  * 4. The names "Xerces" and "Apache Software Foundation" must
48  * not be used to endorse or promote products derived from this
49  * software without prior written permission. For written
50  * permission, please contact apache@apache.org.
51  *
52  * 5. Products derived from this software may not be called "Apache",
53  * nor may "Apache" appear in their name, without prior written
54  * permission of the Apache Software Foundation.
55  *
56  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
57  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
58  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
59  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
60  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
61  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
62  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
63  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
64  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
65  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
66  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67  * SUCH DAMAGE.
68  * ====================================================================
69  *
70  * This software consists of voluntary contributions made by many
71  * individuals on behalf of the Apache Software Foundation and was
72  * originally based on software copyright (c) 1999, International
73  * Business Machines, Inc., http://www.apache.org. For more
74  * information on the Apache Software Foundation, please see
75  * <http://www.apache.org/>.
76  */

77
78 /**
79  * This class provides encode/decode for RFC 2045 Base64 as
80  * defined by RFC 2045, N. Freed and N. Borenstein.
81  * RFC 2045: Multipurpose Internet Mail Extensions (MIME)
82  * Part One: Format of Internet Message Bodies. Reference
83  * 1996 Available at: http://www.ietf.org/rfc/rfc2045.txt
84  * This class is used by XML Schema binary format validation
85  *
86  * This implementation does not encode/decode streaming
87  * data. You need the data that you will encode/decode
88  * already on a byte arrray.
89  *
90  * @author Jeffrey Rodriguez
91  * @author Sandy Gao
92  * @version $Id: Base64.java,v 1.3 2003/09/16 22:48:10 jacobk Exp $
93  */

94 public class Base64 {
95     static private final int BASELENGTH = 255;
96     static private final int LOOKUPLENGTH = 64;
97     static private final int TWENTYFOURBITGROUP = 24;
98     static private final int EIGHTBIT = 8;
99     static private final int SIXTEENBIT = 16;
100     static private final int SIXBIT = 6;
101     static private final int FOURBYTE = 4;
102     static private final int SIGN = -128;
103     static private final byte PAD = (byte) '=';
104     static private final boolean fDebug = false;
105     static private byte [] base64Alphabet = new byte[BASELENGTH];
106     static private byte [] lookUpBase64Alphabet = new byte[LOOKUPLENGTH];
107
108
109     static {
110
111         for (int i = 0; i<BASELENGTH; i++) {
112             base64Alphabet[i] = -1;
113         }
114         for (int i = 'Z'; i >= 'A'; i--) {
115             base64Alphabet[i] = (byte) (i-'A');
116         }
117         for (int i = 'z'; i>= 'a'; i--) {
118             base64Alphabet[i] = (byte) (i-'a' + 26);
119         }
120
121         for (int i = '9'; i >= '0'; i--) {
122             base64Alphabet[i] = (byte) (i-'0' + 52);
123         }
124
125         base64Alphabet['+'] = 62;
126         base64Alphabet['/'] = 63;
127
128         for (int i = 0; i<=25; i++)
129             lookUpBase64Alphabet[i] = (byte) ('A'+i);
130
131         for (int i = 26, j = 0; i<=51; i++, j++)
132             lookUpBase64Alphabet[i] = (byte) ('a'+ j);
133
134         for (int i = 52, j = 0; i<=61; i++, j++)
135             lookUpBase64Alphabet[i] = (byte) ('0' + j);
136         lookUpBase64Alphabet[62] = (byte) '+';
137         lookUpBase64Alphabet[63] = (byte) '/';
138
139     }
140
141     protected static boolean isWhiteSpace (byte octect) {
142         return(octect==0x20 || octect==0xd || octect==0xa || octect==0x9);
143     }
144
145     protected static boolean isPad (byte octect) {
146         return(octect==PAD);
147     }
148
149     protected static boolean isData (byte octect) {
150         return(base64Alphabet[octect]!=-1);
151     }
152
153     public static boolean isBase64(String JavaDoc isValidString) {
154         if (isValidString==null)
155             return false;
156         return(isArrayByteBase64(isValidString.getBytes()));
157     }
158
159
160     public static boolean isBase64(byte octect) {
161         return(isWhiteSpace(octect) || isPad(octect) || isData(octect));
162     }
163
164
165     /**
166      * remove WhiteSpace from MIME containing encoded Base64
167      * data.
168      * e.g.
169      * " sdffferererrereresfsdfsdfsdff\n\r
170      * iiiiiiiiierejrlkwjerklwjerwerwr==\n\r"
171      *
172      * @param data
173      * @return byte array with whitespace removed
174      */

175     public static synchronized byte[] removeWhiteSpace(byte[] data) {
176         if (data==null)
177             return null;
178
179         int newSize = 0;
180         int len = data.length;
181         int i =0;
182         for (; i<len; i++) {
183             if (!isWhiteSpace(data[i]))
184                 newSize++;
185         }
186
187         if (newSize==len)
188             return data;//return input array since no whiteSpace
189

190
191         byte[] arrayWithoutSpaces = new byte[newSize];//Allocate new array without whiteSpace
192

193         int j = 0;
194         for (i=0;i<len;i++) {
195             if (isWhiteSpace(data[i]))
196                 continue;
197             else
198                 arrayWithoutSpaces[j++] = data[i];//copy non-WhiteSpace
199
}
200         return arrayWithoutSpaces;
201
202     }
203
204     public static synchronized boolean isArrayByteBase64(byte[] arrayOctect) {
205         return(getDecodedDataLength(arrayOctect) >= 0);
206     }
207
208     /**
209      * Encodes hex octects into Base64
210      *
211      * @param binaryData Array containing binaryData
212      * @return Encoded Base64 array
213      */

214     public static synchronized byte[] encode(byte[] binaryData) {
215         if (binaryData==null)
216             return null;
217
218         int lengthDataBits = binaryData.length*EIGHTBIT;
219         int fewerThan24bits = lengthDataBits%TWENTYFOURBITGROUP;
220         int numberTriplets = lengthDataBits/TWENTYFOURBITGROUP;
221         byte encodedData[] = null;
222
223
224         if (fewerThan24bits!=0) //data not divisible by 24 bit
225
encodedData = new byte[ (numberTriplets + 1)*4 ];
226         else // 16 or 8 bit
227
encodedData = new byte[ numberTriplets*4 ];
228
229         byte k=0, l=0, b1=0,b2=0,b3=0;
230
231         int encodedIndex = 0;
232         int dataIndex = 0;
233         int i = 0;
234         if (fDebug) {
235             System.out.println("number of triplets = " + numberTriplets);
236         }
237         for (i = 0; i<numberTriplets; i++) {
238
239             dataIndex = i*3;
240             b1 = binaryData[dataIndex];
241             b2 = binaryData[dataIndex + 1];
242             b3 = binaryData[dataIndex + 2];
243
244             if (fDebug) {
245                 System.out.println("b1= " + b1 +", b2= " + b2 + ", b3= " + b3);
246             }
247
248             l = (byte)(b2 & 0x0f);
249             k = (byte)(b1 & 0x03);
250
251             encodedIndex = i*4;
252             byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
253
254             byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
255             byte val3 = ((b3 & SIGN)==0)?(byte)(b3>>6):(byte)((b3)>>6^0xfc);
256
257             encodedData[encodedIndex] = lookUpBase64Alphabet[ val1 ];
258             if (fDebug) {
259                 System.out.println("val2 = " + val2);
260                 System.out.println("k4 = " + (k<<4));
261                 System.out.println("vak = " + (val2 | (k<<4)));
262             }
263
264             encodedData[encodedIndex+1] = lookUpBase64Alphabet[ val2 | (k<<4)];
265             encodedData[encodedIndex+2] = lookUpBase64Alphabet[ (l <<2) | val3 ];
266             encodedData[encodedIndex+3] = lookUpBase64Alphabet[ b3 & 0x3f ];
267         }
268
269         // form integral number of 6-bit groups
270
dataIndex = i*3;
271         encodedIndex = i*4;
272         if (fewerThan24bits==EIGHTBIT) {
273             b1 = binaryData[dataIndex];
274             k = (byte) (b1 &0x03);
275             if (fDebug) {
276                 System.out.println("b1=" + b1);
277                 System.out.println("b1<<2 = " + (b1>>2));
278             }
279             byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
280             encodedData[encodedIndex] = lookUpBase64Alphabet[ val1 ];
281             encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ k<<4 ];
282             encodedData[encodedIndex + 2] = PAD;
283             encodedData[encodedIndex + 3] = PAD;
284         } else if (fewerThan24bits==SIXTEENBIT) {
285
286             b1 = binaryData[dataIndex];
287             b2 = binaryData[dataIndex +1 ];
288             l = (byte) (b2 &0x0f);
289             k = (byte) (b1 &0x03);
290
291             byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
292             byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
293
294             encodedData[encodedIndex] = lookUpBase64Alphabet[ val1 ];
295             encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ val2 | (k<<4)];
296             encodedData[encodedIndex + 2] = lookUpBase64Alphabet[ l<<2 ];
297             encodedData[encodedIndex + 3] = PAD;
298         }
299         return encodedData;
300     }
301     
302     /**
303      * Encodes String into Base64
304      *
305      * @param stringData String containing string data to encode
306      * @return String containing encoded data
307      */

308     public static String JavaDoc encode(String JavaDoc stringData) {
309         if (stringData==null) return null;
310
311         byte[] encoded = encode(stringData.getBytes());
312
313         return (encoded==null) ? null : new String JavaDoc(encoded);
314     }
315     
316     /**
317      * Decodes Base64 data into octects
318      *
319      * @param base64Data Byte array containing Base64 data
320      * @return Array containind decoded data.
321      */

322     public static synchronized byte[] decode(byte[] base64Data) {
323
324         if (base64Data==null)
325             return null;
326
327         byte[] normalizedBase64Data = removeWhiteSpace(base64Data);
328
329         if (normalizedBase64Data.length%FOURBYTE!=0) {
330             return null;//should be divisible by four
331
}
332
333         int numberQuadruple = (normalizedBase64Data.length/FOURBYTE);
334
335         if (numberQuadruple==0)
336             return new byte[0];
337
338         byte decodedData[] = null;
339         byte b1=0,b2=0,b3=0, b4=0, marker0=0, marker1=0;
340         byte d1=0,d2=0,d3=0,d4=0;
341
342
343
344         // Throw away anything not in normalizedBase64Data
345
// Adjust size
346
int i = 0;
347         int encodedIndex = 0;
348         int dataIndex = 0;
349         decodedData = new byte[ (numberQuadruple)*3];
350
351         for (; i<numberQuadruple-1; i++) {
352
353             if (!isData((d1 = normalizedBase64Data[dataIndex++]))||
354                 !isData((d2 = normalizedBase64Data[dataIndex++]))||
355                 !isData((d3 = normalizedBase64Data[dataIndex++]))||
356                 !isData((d4 = normalizedBase64Data[dataIndex++])))
357                 return null;//if found "no data" just return null
358

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

420     public static String JavaDoc decode(String JavaDoc base64Data) {
421         if (base64Data==null) return null;
422
423         byte[] decoded = decode(base64Data.getBytes());
424
425         return (decoded==null) ? null : new String JavaDoc(decoded);
426     }
427
428     /**
429      * returns length of decoded data given an
430      * array containing encoded data.
431      * WhiteSpace removing is done if data array not
432      * valid.
433      *
434      * @param base64Data
435      * @return a -1 would be return if not
436      */

437     static public synchronized int getDecodedDataLength(byte[] base64Data) {
438
439         if (base64Data==null)
440             return -1;
441
442         if (base64Data.length==0)
443             return 0;
444
445         //byte[] normalizedBase64Data = removeWhiteSpace(base64Data);//Remove any whiteSpace
446
byte[] decodedData = null;
447
448         if ((decodedData = decode(base64Data))==null)//decode could return a null byte array
449
return -1;
450
451         return decodedData.length;
452     }
453 }
454
Popular Tags