KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > ojb > broker > util > Base64


1 package org.apache.ojb.broker.util;
2
3 /* Copyright 2002-2005 The Apache Software Foundation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 import org.apache.ojb.broker.util.logging.LoggerFactory;
19
20 public class Base64
21 {
22     
23     /** Specify encoding (value is <tt>true</tt>). */
24     public final static boolean ENCODE = true;
25     
26     
27     /** Specify decoding (value is <tt>false</tt>). */
28     public final static boolean DECODE = false;
29     
30     
31     /** Maximum line length (76) of Base64 output. */
32     private final static int MAX_LINE_LENGTH = 76;
33     
34     
35     /** The equals sign (=) as a byte. */
36     private final static byte EQUALS_SIGN = (byte)'=';
37     
38     
39     /** The new line character (\n) as a byte. */
40     private final static byte NEW_LINE = (byte)'\n';
41     
42     
43     /** The 64 valid Base64 values. */
44     private final static byte[] ALPHABET =
45     {
46         (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
47         (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
48         (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
49         (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
50         (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
51         (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
52         (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
53         (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
54         (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5',
55         (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/'
56     };
57     
58     /**
59      * Translates a Base64 value to either its 6-bit reconstruction value
60      * or a negative number indicating some other meaning.
61      **/

62     private final static byte[] DECODABET =
63     {
64         -9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 0 - 8
65
-5,-5, // Whitespace: Tab and Linefeed
66
-9,-9, // Decimal 11 - 12
67
-5, // Whitespace: Carriage Return
68
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 14 - 26
69
-9,-9,-9,-9,-9, // Decimal 27 - 31
70
-5, // Whitespace: Space
71
-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 33 - 42
72
62, // Plus sign at decimal 43
73
-9,-9,-9, // Decimal 44 - 46
74
63, // Slash at decimal 47
75
52,53,54,55,56,57,58,59,60,61, // Numbers zero through nine
76
-9,-9,-9, // Decimal 58 - 60
77
-1, // Equals sign at decimal 61
78
-9,-9,-9, // Decimal 62 - 64
79
0,1,2,3,4,5,6,7,8,9,10,11,12,13, // Letters 'A' through 'N'
80
14,15,16,17,18,19,20,21,22,23,24,25, // Letters 'O' through 'Z'
81
-9,-9,-9,-9,-9,-9, // Decimal 91 - 96
82
26,27,28,29,30,31,32,33,34,35,36,37,38, // Letters 'a' through 'm'
83
39,40,41,42,43,44,45,46,47,48,49,50,51, // Letters 'n' through 'z'
84
-9,-9,-9,-9 // Decimal 123 - 126
85
/*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 127 - 139
86         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 140 - 152
87         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 153 - 165
88         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 166 - 178
89         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 179 - 191
90         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 192 - 204
91         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 205 - 217
92         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 218 - 230
93         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, // Decimal 231 - 243
94         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9 // Decimal 244 - 255 */

95     };
96     
97     private final static byte BAD_ENCODING = -9; // Indicates error in encoding
98
private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding
99
private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding
100

101     
102     /** Defeats instantiation. */
103     private Base64(){}
104     
105     
106     
107     /**
108      * Testing. Feel free--in fact I encourage you--to throw out
109      * this entire "main" method when you actually deploy this code.
110      */

111     public static void main( String JavaDoc[] args )
112     {
113         try
114         {
115             // Test encoding/decoding byte arrays
116
{
117                 byte[] bytes1 = { (byte)2,(byte)2,(byte)3,(byte)0,(byte)9 }; // My zip code
118
byte[] bytes2 = { (byte)99,(byte)2,(byte)2,(byte)3,(byte)0,(byte)9 };
119                 System.out.println( "Bytes 2,2,3,0,9 as Base64: " + encodeBytes( bytes1 ) );
120                 System.out.println( "Bytes 2,2,3,0,9 w/ offset: " + encodeBytes( bytes2, 1, bytes2.length-1 ) );
121                 byte[] dbytes = decode( encodeBytes( bytes1 ) );
122                 System.out.print( encodeBytes( bytes1 ) + " decoded: " );
123                 for( int i = 0; i < dbytes.length; i++ )
124                     System.out.print( dbytes[i] + (i<dbytes.length-1?",":"\n") );
125             } // end testing byte arrays
126

127             
128             
129             
130             // Test Input Stream
131
{
132                 // Read GIF stored in base64 form.
133
java.io.FileInputStream JavaDoc fis = new java.io.FileInputStream JavaDoc( "test.gif.b64" );
134                 Base64.InputStream b64is = new Base64.InputStream( fis, DECODE );
135
136                 byte[] bytes = new byte[0];
137                 int b = -1;
138                 while( (b = b64is.read()) >= 0 ){
139                     byte[] temp = new byte[ bytes.length + 1 ];
140                     System.arraycopy( bytes,0, temp,0,bytes.length );
141                     temp[bytes.length] = (byte)b;
142                     bytes = temp;
143                 } // end while: terribly inefficient way to read data
144
b64is.close();
145                 javax.swing.ImageIcon JavaDoc iicon = new javax.swing.ImageIcon JavaDoc( bytes );
146                 javax.swing.JLabel JavaDoc jlabel = new javax.swing.JLabel JavaDoc( "Read from test.gif.b64", iicon,0 );
147                 javax.swing.JFrame JavaDoc jframe = new javax.swing.JFrame JavaDoc();
148                 jframe.getContentPane().add( jlabel );
149                 jframe.pack();
150                 jframe.show();
151
152                 // Write raw bytes to file
153
java.io.FileOutputStream JavaDoc fos = new java.io.FileOutputStream JavaDoc( "test.gif_out" );
154                 fos.write( bytes );
155                 fos.close();
156
157                 // Read raw bytes and encode
158
fis = new java.io.FileInputStream JavaDoc( "test.gif_out" );
159                 b64is = new Base64.InputStream( fis, ENCODE );
160                 byte[] ebytes = new byte[0];
161                 b = -1;
162                 while( (b = b64is.read()) >= 0 ){
163                     byte[] temp = new byte[ ebytes.length + 1 ];
164                     System.arraycopy( ebytes,0, temp,0,ebytes.length );
165                     temp[ebytes.length] = (byte)b;
166                     ebytes = temp;
167                 } // end while: terribly inefficient way to read data
168
b64is.close();
169                 String JavaDoc s = new String JavaDoc( ebytes );
170                 javax.swing.JTextArea JavaDoc jta = new javax.swing.JTextArea JavaDoc( s );
171                 javax.swing.JScrollPane JavaDoc jsp = new javax.swing.JScrollPane JavaDoc( jta );
172                 jframe = new javax.swing.JFrame JavaDoc();
173                 jframe.setTitle( "Read from test.gif_out" );
174                 jframe.getContentPane().add( jsp );
175                 jframe.pack();
176                 jframe.show();
177
178                 // Write encoded bytes to file
179
fos = new java.io.FileOutputStream JavaDoc( "test.gif.b64_out" );
180                 fos.write( ebytes );
181
182                 // Read GIF stored in base64 form.
183
fis = new java.io.FileInputStream JavaDoc( "test.gif.b64_out" );
184                 b64is = new Base64.InputStream( fis, DECODE );
185                 byte[] edbytes = new byte[0];
186                 b = -1;
187                 while( (b = b64is.read()) >= 0 ){
188                     byte[] temp = new byte[ edbytes.length + 1 ];
189                     System.arraycopy( edbytes,0, temp,0,edbytes.length );
190                     temp[edbytes.length] = (byte)b;
191                     edbytes = temp;
192                 } // end while: terribly inefficient way to read data
193
b64is.close();
194                 iicon = new javax.swing.ImageIcon JavaDoc( edbytes );
195                 jlabel = new javax.swing.JLabel JavaDoc( "Read from test.gif.b64_out", iicon,0 );
196                 jframe = new javax.swing.JFrame JavaDoc();
197                 jframe.getContentPane().add( jlabel );
198                 jframe.pack();
199                 jframe.show();
200             } // end: Test Input Stream
201

202             
203             // Test Output Stream
204
{
205                 // Read raw bytes
206
java.io.FileInputStream JavaDoc fis = new java.io.FileInputStream JavaDoc( "test.gif_out" );
207                 byte[] rbytes = new byte[0];
208                 int b = -1;
209                 while( (b = fis.read()) >= 0 ){
210                     byte[] temp = new byte[ rbytes.length + 1 ];
211                     System.arraycopy( rbytes,0, temp,0,rbytes.length );
212                     temp[rbytes.length] = (byte)b;
213                     rbytes = temp;
214                 } // end while: terribly inefficient way to read data
215
fis.close();
216                 
217                 // Write raw bytes to encoded file
218
java.io.FileOutputStream JavaDoc fos = new java.io.FileOutputStream JavaDoc("test.gif.b64_out2");
219                 Base64.OutputStream b64os = new Base64.OutputStream( fos, ENCODE );
220                 b64os.write( rbytes );
221                 b64os.close();
222                 
223                 
224                 // Read raw bytes that are actually encoded (but we'll ignore that)
225
fis = new java.io.FileInputStream JavaDoc( "test.gif.b64_out2" );
226                 byte[] rebytes = new byte[0];
227                 b = -1;
228                 while( (b = fis.read()) >= 0 ){
229                     byte[] temp = new byte[ rebytes.length + 1 ];
230                     System.arraycopy( rebytes,0, temp,0,rebytes.length );
231                     temp[rebytes.length] = (byte)b;
232                     rebytes = temp;
233                 } // end while: terribly inefficient way to read data
234
fis.close();
235                 String JavaDoc s = new String JavaDoc( rebytes );
236                 javax.swing.JTextArea JavaDoc jta = new javax.swing.JTextArea JavaDoc( s );
237                 javax.swing.JScrollPane JavaDoc jsp = new javax.swing.JScrollPane JavaDoc( jta );
238                 javax.swing.JFrame JavaDoc jframe = new javax.swing.JFrame JavaDoc();
239                 jframe.setTitle( "Read from test.gif.b64_out2" );
240                 jframe.getContentPane().add( jsp );
241                 jframe.pack();
242                 jframe.show();
243                
244                 // Write encoded bytes to decoded raw file
245
fos = new java.io.FileOutputStream JavaDoc("test.gif_out2");
246                 b64os = new Base64.OutputStream( fos, DECODE );
247                 b64os.write( rebytes );
248                 b64os.close();
249                 javax.swing.ImageIcon JavaDoc iicon = new javax.swing.ImageIcon JavaDoc( "test.gif_out2" );
250                 javax.swing.JLabel JavaDoc jlabel = new javax.swing.JLabel JavaDoc( "Read from test.gif_out2", iicon,0 );
251                 jframe = new javax.swing.JFrame JavaDoc();
252                 jframe.getContentPane().add( jlabel );
253                 jframe.pack();
254                 jframe.show();
255                
256             } // end: Test Output Stream
257

258             
259             // Test wagner's files
260
{
261                 java.io.FileInputStream JavaDoc fis = new java.io.FileInputStream JavaDoc("D:\\temp\\testencoding.txt");
262                 Base64.InputStream b64is = new Base64.InputStream( fis, DECODE );
263                 java.io.FileOutputStream JavaDoc fos = new java.io.FileOutputStream JavaDoc("D:\\temp\\file.zip");
264                 int b;
265                 while( (b=b64is.read()) >= 0 )
266                     fos.write( b );
267                 fos.close();
268                 b64is.close();
269             
270             } // end test wagner's file
271

272         } // end try
273
catch( Exception JavaDoc e)
274         { e.printStackTrace();
275         }
276     } // end main
277

278     
279 /* ******** E N C O D I N G M E T H O D S ******** */
280     
281     
282     /**
283      * Encodes the first three bytes of array <var>threeBytes</var>
284      * and returns a four-byte array in Base64 notation.
285      *
286      * @param threeBytes the array to convert
287      * @return four byte array in Base64 notation.
288      * @since 1.3
289      */

290     private static byte[] encode3to4( byte[] threeBytes )
291     { return encode3to4( threeBytes, 3 );
292     } // end encodeToBytes
293

294     
295     
296     /**
297      * Encodes up to the first three bytes of array <var>threeBytes</var>
298      * and returns a four-byte array in Base64 notation.
299      * The actual number of significant bytes in your array is
300      * given by <var>numSigBytes</var>.
301      * The array <var>threeBytes</var> needs only be as big as
302      * <var>numSigBytes</var>.
303      *
304      * @param threeBytes the array to convert
305      * @param numSigBytes the number of significant bytes in your array
306      * @return four byte array in Base64 notation.
307      * @since 1.3
308      */

309     private static byte[] encode3to4( byte[] threeBytes, int numSigBytes )
310     { byte[] dest = new byte[4];
311         encode3to4( threeBytes, 0, numSigBytes, dest, 0 );
312         return dest;
313     }
314     
315     
316     
317     /**
318      * Encodes up to three bytes of the array <var>source</var>
319      * and writes the resulting four Base64 bytes to <var>destination</var>.
320      * The source and destination arrays can be manipulated
321      * anywhere along their length by specifying
322      * <var>srcOffset</var> and <var>destOffset</var>.
323      * This method does not check to make sure your arrays
324      * are large enough to accomodate <var>srcOffset</var> + 3 for
325      * the <var>source</var> array or <var>destOffset</var> + 4 for
326      * the <var>destination</var> array.
327      * The actual number of significant bytes in your array is
328      * given by <var>numSigBytes</var>.
329      *
330      * @param source the array to convert
331      * @param srcOffset the index where conversion begins
332      * @param numSigBytes the number of significant bytes in your array
333      * @param destination the array to hold the conversion
334      * @param destOffset the index where output will be put
335      * @return the <var>destination</var> array
336      * @since 1.3
337      */

338     private static byte[] encode3to4(
339      byte[] source, int srcOffset, int numSigBytes,
340      byte[] destination, int destOffset )
341     {
342         // 1 2 3
343
// 01234567890123456789012345678901 Bit position
344
// --------000000001111111122222222 Array position from threeBytes
345
// --------| || || || | Six bit groups to index ALPHABET
346
// >>18 >>12 >> 6 >> 0 Right shift necessary
347
// 0x3f 0x3f 0x3f Additional AND
348

349         // Create buffer with zero-padding if there are only one or two
350
// significant bytes passed in the array.
351
// We have to shift left 24 in order to flush out the 1's that appear
352
// when Java treats a value as negative that is cast from a byte to an int.
353
int inBuff = ( numSigBytes > 0 ? ((source[ srcOffset ] << 24) >>> 8) : 0 )
354                      | ( numSigBytes > 1 ? ((source[ srcOffset + 1 ] << 24) >>> 16) : 0 )
355                      | ( numSigBytes > 2 ? ((source[ srcOffset + 2 ] << 24) >>> 24) : 0 );
356
357         switch( numSigBytes )
358         {
359             case 3:
360                 destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
361                 destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
362                 destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ];
363                 destination[ destOffset + 3 ] = ALPHABET[ (inBuff ) & 0x3f ];
364                 return destination;
365                 
366             case 2:
367                 destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
368                 destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
369                 destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ];
370                 destination[ destOffset + 3 ] = EQUALS_SIGN;
371                 return destination;
372                 
373             case 1:
374                 destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
375                 destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
376                 destination[ destOffset + 2 ] = EQUALS_SIGN;
377                 destination[ destOffset + 3 ] = EQUALS_SIGN;
378                 return destination;
379                 
380             default:
381                 return destination;
382         } // end switch
383
} // end encode3to4
384

385     /**
386      * Serializes an object and returns the Base64-encoded
387      * version of that serialized object. If the object
388      * cannot be serialized or there is another error,
389      * the method will return <tt>null</tt>.
390      *
391      * @param serializableObject The object to encode
392      * @return The Base64-encoded object
393      * @since 1.4
394      */

395     public static String JavaDoc encodeObject( java.io.Serializable JavaDoc serializableObject )
396     {
397         return encodeObject( serializableObject, true );
398     } // end encodeObject
399

400     /**
401      * Serializes an object and returns the Base64-encoded
402      * version of that serialized object. If the object
403      * cannot be serialized or there is another error,
404      * the method will return <tt>null</tt>.
405      *
406      * @param serializableObject The object to encode
407      * @param breakLines Break lines at 80 characters or less.
408      * @return The Base64-encoded object
409      * @since 1.4
410      */

411     public static String JavaDoc encodeObject(java.io.Serializable JavaDoc serializableObject, boolean breakLines)
412     {
413         java.io.ByteArrayOutputStream JavaDoc baos = null;
414         java.io.OutputStream JavaDoc b64os = null;
415         java.io.ObjectOutputStream JavaDoc oos = null;
416
417         try
418         {
419             baos = new java.io.ByteArrayOutputStream JavaDoc();
420             b64os = new Base64.OutputStream(baos, Base64.ENCODE, breakLines);
421             oos = new java.io.ObjectOutputStream JavaDoc(b64os);
422
423             oos.writeObject(serializableObject);
424         } // end try
425
catch (java.io.IOException JavaDoc e)
426         {
427             e.printStackTrace();
428             return null;
429         } // end catch
430
finally
431         {
432             try
433             {
434                 oos.close();
435             }
436             catch (Exception JavaDoc e)
437             {
438                 // ignore it
439
}
440             try
441             {
442                 b64os.close();
443             }
444             catch (Exception JavaDoc e)
445             {
446                 // ignore it
447
}
448             try
449             {
450                 baos.close();
451             }
452             catch (Exception JavaDoc e)
453             {
454                 // ignore it
455
}
456         } // end finally
457

458         return new String JavaDoc(baos.toByteArray());
459     } // end encode
460

461     
462     /**
463      * Encodes a byte array into Base64 notation.
464      * Equivalen to calling
465      * <code>encodeBytes( source, 0, source.length )</code>
466      *
467      * @param source The data to convert
468      * @since 1.4
469      */

470     public static String JavaDoc encodeBytes( byte[] source )
471     {
472         return encodeBytes( source, true );
473     } // end encodeBytes
474

475     /**
476      * Encodes a byte array into Base64 notation.
477      * Equivalen to calling
478      * <code>encodeBytes( source, 0, source.length )</code>
479      *
480      * @param source The data to convert
481      * @param breakLines Break lines at 80 characters or less.
482      * @since 1.4
483      */

484     public static String JavaDoc encodeBytes( byte[] source, boolean breakLines )
485     {
486         return encodeBytes( source, 0, source.length, breakLines );
487     } // end encodeBytes
488

489     
490     /**
491      * Encodes a byte array into Base64 notation.
492      *
493      * @param source The data to convert
494      * @param off Offset in array where conversion should begin
495      * @param len Length of data to convert
496      * @since 1.4
497      */

498     public static String JavaDoc encodeBytes( byte[] source, int off, int len )
499     {
500         return encodeBytes( source, off, len, true );
501     } // end encodeBytes
502

503     
504     /**
505      * Encodes a byte array into Base64 notation.
506      *
507      * @param source The data to convert
508      * @param off Offset in array where conversion should begin
509      * @param len Length of data to convert
510      * @param breakLines Break lines at 80 characters or less.
511      * @since 1.4
512      */

513     public static String JavaDoc encodeBytes( byte[] source, int off, int len, boolean breakLines )
514     {
515         int len43 = len * 4 / 3;
516         byte[] outBuff = new byte[ ( len43 ) // Main 4:3
517
+ ( (len % 3) > 0 ? 4 : 0 ) // Account for padding
518
+ (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines
519
int d = 0;
520         int e = 0;
521         int len2 = len - 2;
522         int lineLength = 0;
523         for( ; d < len2; d+=3, e+=4 )
524         {
525             encode3to4( source, d+off, 3, outBuff, e );
526             
527             lineLength += 4;
528             if( breakLines && lineLength == MAX_LINE_LENGTH )
529             {
530                 outBuff[e+4] = NEW_LINE;
531                 e++;
532                 lineLength = 0;
533             } // end if: end of line
534
} // en dfor: each piece of array
535

536         if( d < len )
537         {
538             encode3to4( source, d+off, len - d, outBuff, e );
539             e += 4;
540         } // end if: some padding needed
541

542         return new String JavaDoc( outBuff, 0, e );
543     } // end encodeBytes
544

545     
546     /**
547      * Encodes a string in Base64 notation with line breaks
548      * after every 75 Base64 characters.
549      *
550      * @param s the string to encode
551      * @return the encoded string
552      * @since 1.3
553      */

554     public static String JavaDoc encodeString( String JavaDoc s )
555     {
556         return encodeString( s, true );
557     } // end encodeString
558

559     /**
560      * Encodes a string in Base64 notation with line breaks
561      * after every 75 Base64 characters.
562      *
563      * @param s the string to encode
564      * @param breakLines Break lines at 80 characters or less.
565      * @return the encoded string
566      * @since 1.3
567      */

568     public static String JavaDoc encodeString( String JavaDoc s, boolean breakLines )
569     {
570         return encodeBytes( s.getBytes(), breakLines );
571     } // end encodeString
572

573     
574     
575     
576 /* ******** D E C O D I N G M E T H O D S ******** */
577     
578     
579     /**
580      * Decodes the first four bytes of array <var>fourBytes</var>
581      * and returns an array up to three bytes long with the
582      * decoded values.
583      *
584      * @param fourBytes the array with Base64 content
585      * @return array with decoded values
586      * @since 1.3
587      */

588     private static byte[] decode4to3( byte[] fourBytes )
589     {
590         byte[] outBuff1 = new byte[3];
591         int count = decode4to3( fourBytes, 0, outBuff1, 0 );
592         byte[] outBuff2 = new byte[ count ];
593         
594         System.arraycopy( outBuff1, 0, outBuff2, 0, count );
595         return outBuff2;
596     }
597     
598     
599     
600     
601     /**
602      * Decodes four bytes from array <var>source</var>
603      * and writes the resulting bytes (up to three of them)
604      * to <var>destination</var>.
605      * The source and destination arrays can be manipulated
606      * anywhere along their length by specifying
607      * <var>srcOffset</var> and <var>destOffset</var>.
608      * This method does not check to make sure your arrays
609      * are large enough to accomodate <var>srcOffset</var> + 4 for
610      * the <var>source</var> array or <var>destOffset</var> + 3 for
611      * the <var>destination</var> array.
612      * This method returns the actual number of bytes that
613      * were converted from the Base64 encoding.
614      *
615      *
616      * @param source the array to convert
617      * @param srcOffset the index where conversion begins
618      * @param destination the array to hold the conversion
619      * @param destOffset the index where output will be put
620      * @return the number of decoded bytes converted
621      * @since 1.3
622      */

623     private static int decode4to3( byte[] source, int srcOffset, byte[] destination, int destOffset )
624     {
625         // Example: Dk==
626
if( source[ srcOffset + 2] == EQUALS_SIGN )
627         {
628             // Two ways to do the same thing. Don't know which way I like best.
629
//int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
630
// | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );
631
int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )
632                           | ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 );
633             
634             destination[ destOffset ] = (byte)( outBuff >>> 16 );
635             return 1;
636         }
637         
638         // Example: DkL=
639
else if( source[ srcOffset + 3 ] == EQUALS_SIGN )
640         {
641             // Two ways to do the same thing. Don't know which way I like best.
642
//int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
643
// | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
644
// | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 );
645
int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )
646                           | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
647                           | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6 );
648             
649             destination[ destOffset ] = (byte)( outBuff >>> 16 );
650             destination[ destOffset + 1 ] = (byte)( outBuff >>> 8 );
651             return 2;
652         }
653         
654         // Example: DkLE
655
else
656         {
657             try{
658             // Two ways to do the same thing. Don't know which way I like best.
659
//int outBuff = ( ( DECODABET[ source[ srcOffset ] ] << 24 ) >>> 6 )
660
// | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
661
// | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 )
662
// | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 );
663
int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )
664                           | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
665                           | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6)
666                           | ( ( DECODABET[ source[ srcOffset + 3 ] ] & 0xFF ) );
667
668             
669             destination[ destOffset ] = (byte)( outBuff >> 16 );
670             destination[ destOffset + 1 ] = (byte)( outBuff >> 8 );
671             destination[ destOffset + 2 ] = (byte)( outBuff );
672
673             return 3;
674             }catch( Exception JavaDoc e){
675                 LoggerFactory.getDefaultLogger().error(""+source[srcOffset]+ ": " + ( DECODABET[ source[ srcOffset ] ] ) );
676                 LoggerFactory.getDefaultLogger().error(""+source[srcOffset+1]+ ": " + ( DECODABET[ source[ srcOffset + 1 ] ] ) );
677                 LoggerFactory.getDefaultLogger().error(""+source[srcOffset+2]+ ": " + ( DECODABET[ source[ srcOffset + 2 ] ] ) );
678                 LoggerFactory.getDefaultLogger().error(""+source[srcOffset+3]+ ": " + ( DECODABET[ source[ srcOffset + 3 ] ] ) );
679                 return -1;
680             } // end catch
681
}
682     } // end decodeToBytes
683

684     
685     
686     /**
687      * Decodes data from Base64 notation.
688      *
689      * @param s the string to decode
690      * @return the decoded data
691      * @since 1.4
692      */

693     public static byte[] decode( String JavaDoc s )
694     {
695         byte[] bytes = s.getBytes();
696         return decode( bytes, 0, bytes.length );
697     } // end decode
698

699     
700     /**
701      * Decodes data from Base64 notation and
702      * returns it as a string.
703