KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xerces > internal > impl > dv > util > 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 com.sun.org.apache.xerces.internal.impl.dv.util;
59
60 /**
61  * This class provides encode/decode for RFC 2045 Base64 as
62  * defined by RFC 2045, N. Freed and N. Borenstein.
63  * RFC 2045: Multipurpose Internet Mail Extensions (MIME)
64  * Part One: Format of Internet Message Bodies. Reference
65  * 1996 Available at: http://www.ietf.org/rfc/rfc2045.txt
66  * This class is used by XML Schema binary format validation
67  *
68  * This implementation does not encode/decode streaming
69  * data. You need the data that you will encode/decode
70  * already on a byte arrray.
71  *
72  * @author Jeffrey Rodriguez
73  * @author Sandy Gao
74  * @version $Id: Base64.java,v 1.8 2003/05/08 20:11:55 elena Exp $
75  */

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

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

274     public static byte[] decode(String JavaDoc encoded) {
275
276         if (encoded == null)
277             return null;
278
279         char[] base64Data = encoded.toCharArray();
280         // remove white spaces
281
int len = removeWhiteSpace(base64Data);
282         
283         if (len%FOURBYTE != 0) {
284             return null;//should be divisible by four
285
}
286
287         int numberQuadruple = (len/FOURBYTE );
288
289         if (numberQuadruple == 0)
290             return new byte[0];
291
292         byte decodedData[] = null;
293         byte b1=0,b2=0,b3=0, b4=0, marker0=0, marker1=0;
294         char d1=0,d2=0,d3=0,d4=0;
295
296         int i = 0;
297         int encodedIndex = 0;
298         int dataIndex = 0;
299         decodedData = new byte[ (numberQuadruple)*3];
300
301         for (; i<numberQuadruple-1; i++) {
302
303             if (!isData( (d1 = base64Data[dataIndex++]) )||
304                 !isData( (d2 = base64Data[dataIndex++]) )||
305                 !isData( (d3 = base64Data[dataIndex++]) )||
306                 !isData( (d4 = base64Data[dataIndex++]) ))
307                 return null;//if found "no data" just return null
308

309             b1 = base64Alphabet[d1];
310             b2 = base64Alphabet[d2];
311             b3 = base64Alphabet[d3];
312             b4 = base64Alphabet[d4];
313
314             decodedData[encodedIndex++] = (byte)( b1 <<2 | b2>>4 ) ;
315             decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
316             decodedData[encodedIndex++] = (byte)( b3<<6 | b4 );
317         }
318
319         if (!isData( (d1 = base64Data[dataIndex++]) ) ||
320             !isData( (d2 = base64Data[dataIndex++]) )) {
321             return null;//if found "no data" just return null
322
}
323
324         b1 = base64Alphabet[d1];
325         b2 = base64Alphabet[d2];
326
327         d3 = base64Data[dataIndex++];
328         d4 = base64Data[dataIndex++];
329         if (!isData( (d3 ) ) ||
330             !isData( (d4 ) )) {//Check if they are PAD characters
331
if (isPad( d3 ) && isPad( d4)) { //Two PAD e.g. 3c[Pad][Pad]
332
if ((b2 & 0xf) != 0)//last 4 bits should be zero
333
return null;
334                 byte[] tmp = new byte[ i*3 + 1 ];
335                 System.arraycopy( decodedData, 0, tmp, 0, i*3 );
336                 tmp[encodedIndex] = (byte)( b1 <<2 | b2>>4 ) ;
337                 return tmp;
338             } else if (!isPad( d3) && isPad(d4)) { //One PAD e.g. 3cQ[Pad]
339
b3 = base64Alphabet[ d3 ];
340                 if ((b3 & 0x3 ) != 0)//last 2 bits should be zero
341
return null;
342                 byte[] tmp = new byte[ i*3 + 2 ];
343                 System.arraycopy( decodedData, 0, tmp, 0, i*3 );
344                 tmp[encodedIndex++] = (byte)( b1 <<2 | b2>>4 );
345                 tmp[encodedIndex] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
346                 return tmp;
347             } else {
348                 return null;//an error like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data
349
}
350         } else { //No PAD e.g 3cQl
351
b3 = base64Alphabet[ d3 ];
352             b4 = base64Alphabet[ d4 ];
353             decodedData[encodedIndex++] = (byte)( b1 <<2 | b2>>4 ) ;
354             decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
355             decodedData[encodedIndex++] = (byte)( b3<<6 | b4 );
356
357         }
358
359         return decodedData;
360     }
361
362     /**
363      * remove WhiteSpace from MIME containing encoded Base64 data.
364      *
365      * @param data the byte array of base64 data (with WS)
366      * @return the new length
367      */

368     protected static int removeWhiteSpace(char[] data) {
369         if (data == null)
370             return 0;
371
372         // count characters that's not whitespace
373
int newSize = 0;
374         int len = data.length;
375         for (int i = 0; i < len; i++) {
376             if (!isWhiteSpace(data[i]))
377                 data[newSize++] = data[i];
378         }
379         return newSize;
380     }
381 }
382
Popular Tags