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      * Equivlaent to calling
704      * <code>new String( decode( s ) )</code>
705      *
706      * @param s the strind to decode
707      * @return The data as a string
708      * @since 1.4
709      */

710     public static String JavaDoc decodeToString( String JavaDoc s )
711     { return new String JavaDoc( decode( s ) );
712     } // end decodeToString
713

714     
715     /**
716      * Attempts to decode Base64 data and deserialize a Java
717      * Object within. Returns <tt>null if there was an error.
718      *
719      * @param encodedObject The Base64 data to decode
720      * @return The decoded and deserialized object
721      * @since 1.4
722      */

723     public static Object JavaDoc decodeToObject(String JavaDoc encodedObject)
724     {
725         byte[] objBytes = decode(encodedObject);
726
727         java.io.ByteArrayInputStream JavaDoc bais = null;
728         java.io.ObjectInputStream JavaDoc ois = null;
729
730         try
731         {
732             bais = new java.io.ByteArrayInputStream JavaDoc(objBytes);
733             ois = new java.io.ObjectInputStream JavaDoc(bais);
734
735             return ois.readObject();
736         } // end try
737
catch (java.io.IOException JavaDoc e)
738         {
739             e.printStackTrace();
740             return null;
741         } // end catch
742
catch (java.lang.ClassNotFoundException JavaDoc e)
743         {
744             e.printStackTrace();
745             return null;
746         } // end catch
747
finally
748         {
749             try
750             {
751                 bais.close();
752             }
753             catch (Exception JavaDoc e)
754             {
755                 // ignore it
756
}
757             try
758             {
759                 ois.close();
760             }
761             catch (Exception JavaDoc e)
762             {
763                 // ignore it
764
}
765         } // end finally
766
} // end decodeObject
767

768     
769     /**
770      * Decodes Base64 content in byte array format and returns
771      * the decoded byte array.
772      *
773      * @param source The Base64 encoded data
774      * @param off The offset of where to begin decoding
775      * @param len The length of characters to decode
776      * @return decoded data
777      * @since 1.3
778      */

779     public static byte[] decode( byte[] source, int off, int len )
780     {
781         int len34 = len * 3 / 4;
782         byte[] outBuff = new byte[ len34 ]; // Upper limit on size of output
783
int outBuffPosn = 0;
784         
785         byte[] b4 = new byte[4];
786         int b4Posn = 0;
787         int i = 0;
788         byte sbiCrop = 0;
789         byte sbiDecode = 0;
790         for( i = 0; i < len; i++ )
791         {
792             sbiCrop = (byte)(source[i] & 0x7f); // Only the low seven bits
793
sbiDecode = DECODABET[ sbiCrop ];
794             
795             if( sbiDecode >= WHITE_SPACE_ENC ) // White space, Equals sign or better
796
{
797                 if( sbiDecode >= EQUALS_SIGN_ENC )
798                 {
799                     b4[ b4Posn++ ] = sbiCrop;
800                     if( b4Posn > 3 )
801                     {
802                         outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn );
803                         b4Posn = 0;
804                         
805                         // If that was the equals sign, break out of 'for' loop
806
if( sbiCrop == EQUALS_SIGN )
807                             break;
808                     } // end if: quartet built
809

810                 } // end if: equals sign or better
811

812             } // end if: white space, equals sign or better
813
else
814             {
815                 LoggerFactory.getDefaultLogger().error( "Bad Base64 input character at " + i + ": " + source[i] + "(decimal)" );
816                 return null;
817             } // end else:
818
} // each input character
819

820         byte[] out = new byte[ outBuffPosn ];
821         System.arraycopy( outBuff, 0, out, 0, outBuffPosn );
822         return out;
823     } // end decode
824

825     
826     
827     
828     /* ******** I N N E R C L A S S I N P U T S T R E A M ******** */
829     
830     
831     
832     /**
833      * A {@link Base64.InputStream} will read data from another
834      * {@link java.io.InputStream}, given in the constructor,
835      * and encode/decode to/from Base64 notation on the fly.
836      *
837      * @see Base64
838      * @see java.io.FilterInputStream
839      * @since 1.3
840      */

841     public static class InputStream extends java.io.FilterInputStream JavaDoc
842     {
843         private boolean encode; // Encoding or decoding
844
private int position; // Current position in the buffer
845
private byte[] buffer; // Small buffer holding converted data
846
private int bufferLength; // Length of buffer (3 or 4)
847
private int numSigBytes; // Number of meaningful bytes in the buffer
848
private int lineLength;
849         private boolean breakLines; // Break lines at less than 80 characters
850

851         
852         /**
853          * Constructs a {@link Base64.InputStream} in DECODE mode.
854          *
855          * @param in the {@link java.io.InputStream} from which to read data.
856          * @since 1.3
857          */

858         public InputStream( java.io.InputStream JavaDoc in )
859         {
860             this( in, Base64.DECODE );
861         } // end constructor
862

863         
864         /**
865          * Constructs a {@link Base64.InputStream} in
866          * either ENCODE or DECODE mode.
867          *
868          * @param in the {@link java.io.InputStream} from which to read data.
869          * @param encode Conversion direction
870          * @see Base64#ENCODE
871          * @see Base64#DECODE
872          * @since 1.3
873          */

874         public InputStream( java.io.InputStream JavaDoc in, boolean encode )
875         {
876             this( in, encode, true );
877         } // end constructor
878

879         
880         /**
881          * Constructs a {@link Base64.InputStream} in
882          * either ENCODE or DECODE mode.
883          *
884          * @param in the {@link java.io.InputStream} from which to read data.
885          * @param encode Conversion direction
886          * @param breakLines Break lines at less than 80 characters.
887          * @see Base64#ENCODE
888          * @see Base64#DECODE
889          * @since 1.3
890          */

891         public InputStream( java.io.InputStream JavaDoc in, boolean encode, boolean breakLines )
892         {
893             super( in );
894             this.breakLines = breakLines;
895             this.encode = encode;
896             this.bufferLength = encode ? 4 : 3;
897             this.buffer = new byte[ bufferLength ];
898             this.position = -1;
899             this.lineLength = 0;
900         } // end constructor
901

902         /**
903          * Reads enough of the input stream to convert
904          * to/from Base64 and returns the next byte.
905          *
906          * @return next byte
907          * @since 1.3
908          */

909         public int read() throws java.io.IOException JavaDoc
910         {
911             // Do we need to get data?
912
if( position < 0 )
913             {
914                 if( encode )
915                 {
916                     byte[] b3 = new byte[3];
917                     int numBinaryBytes = 0;
918                     for( int i = 0; i < 3; i++ )
919                     {
920                         try
921                         {
922                             int b = in.read();
923                             
924                             // If end of stream, b is -1.
925
if( b >= 0 )
926                             {
927                                 b3[i] = (byte)b;
928                                 numBinaryBytes++;
929                             } // end if: not end of stream
930

931                         } // end try: read
932
catch( java.io.IOException JavaDoc e )
933                         {
934                             // Only a problem if we got no data at all.
935
if( i == 0 )
936                                 throw e;
937                             
938                         } // end catch
939
} // end for: each needed input byte
940

941                     if( numBinaryBytes > 0 )
942                     {
943                         encode3to4( b3, 0, numBinaryBytes, buffer, 0 );
944                         position = 0;
945                         numSigBytes = 4;
946                     } // end if: got data
947
else
948                     {
949                         return -1;
950                     } // end else
951
} // end if: encoding
952

953                 // Else decoding
954
else
955                 {
956                     byte[] b4 = new byte[4];
957                     int i = 0;
958                     for( i = 0; i < 4; i++ )
959                     {
960                         // Read four "meaningful" bytes:
961
int b = 0;
962                         do{ b = in.read(); }
963                         while( b >= 0 && DECODABET[ b & 0x7f ] <= WHITE_SPACE_ENC );
964                         
965                         if( b < 0 )
966                             break; // Reads a -1 if end of stream
967

968                         b4[i] = (byte)b;
969                     } // end for: each needed input byte
970

971                     if( i == 4 )
972                     {
973                         numSigBytes = decode4to3( b4, 0, buffer, 0 );
974                         position = 0;
975                     } // end if: got four characters
976
else if( i == 0 ){
977                         return -1;
978                     } // end else if: also padded correctly
979
else
980                     {
981                         // Must have broken out from above.
982
throw new java.io.IOException JavaDoc( "Improperly padded Base64 input." );
983                     } // end
984

985                 } // end else: decode
986
} // end else: get data
987

988             // Got data?
989
if( position >= 0 )
990             {
991                 // End of relevant data?
992
if( /*!encode &&*/ position >= numSigBytes )
993                     return -1;
994                 
995                 if( encode && breakLines && lineLength >= MAX_LINE_LENGTH )
996                 {
997                     lineLength = 0;
998                     return '\n';
999                 } // end if
1000
else
1001                {
1002                    lineLength++; // This isn't important when decoding
1003
// but throwing an extra "if" seems
1004
// just as wasteful.
1005

1006                    int b = buffer[ position++ ];
1007
1008                    if( position >= bufferLength )
1009                        position = -1;
1010
1011                    return b & 0xFF; // This is how you "cast" a byte that's
1012
// intended to be unsigned.
1013
} // end else
1014
} // end if: position >= 0
1015

1016            // Else error
1017
else
1018            {
1019                // When JDK1.4 is more accepted, use an assertion here.
1020
throw new java.io.IOException JavaDoc( "Error in Base64 code reading stream." );
1021            } // end else
1022
} // end read
1023

1024        
1025        /**
1026         * Calls {@link #read} repeatedly until the end of stream
1027         * is reached or <var>len</var> bytes are read.
1028         * Returns number of bytes read into array or -1 if
1029         * end of stream is encountered.
1030         *
1031         * @param dest array to hold values
1032         * @param off offset for array
1033         * @param len max number of bytes to read into array
1034         * @return bytes read into array or -1 if end of stream is encountered.
1035         * @since 1.3
1036         */

1037        public int read( byte[] dest, int off, int len ) throws java.io.IOException JavaDoc
1038        {
1039            int i;
1040            int b;
1041            for( i = 0; i < len; i++ )
1042            {
1043                b = read();
1044                
1045                //if( b < 0 && i == 0 )
1046
// return -1;
1047

1048                if( b >= 0 )
1049                    dest[off + i] = (byte)b;
1050                else if( i == 0 )
1051                    return -1;
1052                else
1053                    break; // Out of 'for' loop
1054
} // end for: each byte read
1055
return i;
1056        } // end read
1057

1058    } // end inner class InputStream
1059

1060    
1061    
1062    
1063    
1064    
1065    /* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */
1066    
1067    
1068    
1069    /**
1070     * A {@link Base64.OutputStream} will write data to another
1071     * {@link java.io.OutputStream}, given in the constructor,
1072     * and encode/decode to/from Base64 notation on the fly.
1073     *
1074     * @see Base64
1075     * @see java.io.FilterOutputStream
1076     * @since 1.3
1077     */

1078    public static class OutputStream extends java.io.FilterOutputStream JavaDoc
1079    {
1080        private boolean encode;
1081        private int position;
1082        private byte[] buffer;
1083        private int bufferLength;
1084        private int lineLength;
1085        private boolean breakLines;
1086        
1087        
1088        /**
1089         * Constructs a {@link Base64.OutputStream} in ENCODE mode.
1090         *
1091         * @param out the {@link java.io.OutputStream} to which data will be written.
1092         * @since 1.3
1093         */

1094        public OutputStream( java.io.OutputStream JavaDoc out )
1095        {
1096            this( out, Base64.ENCODE );
1097        } // end constructor
1098

1099        
1100        /**
1101         * Constructs a {@link Base64.OutputStream} in
1102         * either ENCODE or DECODE mode.
1103         *
1104         * @param out the {@link java.io.OutputStream} to which data will be written.
1105         * @param encode Conversion direction
1106         * @see Base64#ENCODE
1107         * @see Base64#DECODE
1108         * @since 1.3
1109         */

1110        public OutputStream( java.io.OutputStream JavaDoc out, boolean encode )
1111        {
1112            this( out, encode, true );
1113        } // end constructor
1114

1115        
1116        /**
1117         * Constructs a {@link Base64.OutputStream} in
1118         * either ENCODE or DECODE mode.
1119         *
1120         * @param out the {@link java.io.OutputStream} to which data will be written.
1121         * @param encode Conversion direction
1122         * @param breakLines Break lines to be less than 80 characters.
1123         * @see Base64#ENCODE
1124         * @see Base64#DECODE
1125         * @since 1.3
1126         */

1127        public OutputStream( java.io.OutputStream JavaDoc out, boolean encode, boolean breakLines )
1128        {
1129            super( out );
1130            this.breakLines = breakLines;
1131            this.encode = encode;
1132            this.bufferLength = encode ? 3 : 4;
1133            this.buffer = new byte[ bufferLength ];
1134            this.position = 0;
1135            this.lineLength = 0;
1136        } // end constructor
1137

1138        
1139        /**
1140         * Writes the byte to the output stream after
1141         * converting to/from Base64 notation.
1142         * When encoding, bytes are buffered three
1143         * at a time before the output stream actually
1144         * gets a write() call.
1145         * When decoding, bytes are buffered four
1146         * at a time.
1147         *
1148         * @param theByte the byte to write
1149         * @since 1.3
1150         */

1151        public void write(int theByte) throws java.io.IOException JavaDoc
1152        {
1153            if( encode )
1154            {
1155                buffer[ position++ ] = (byte)theByte;
1156                if( position >= bufferLength ) // Enough to encode.
1157
{
1158                    out.write( Base64.encode3to4( buffer, bufferLength ) );
1159                    
1160                    lineLength += 4;
1161                    if( breakLines && lineLength >= MAX_LINE_LENGTH )
1162                    {
1163                        out.write( NEW_LINE );
1164                        lineLength = 0;
1165                    } // end if: end of line
1166

1167                    position = 0;
1168                } // end if: enough to output
1169
} // end if: encoding
1170

1171            // Else, Decoding
1172
else
1173            {
1174                // Meaningful Base64 character?
1175
if( DECODABET[ theByte & 0x7f ] > WHITE_SPACE_ENC )
1176                {
1177                    buffer[ position++ ] = (byte)theByte;
1178                    if( position >= bufferLength ) // Enough to output.
1179
{
1180                        out.write( Base64.decode4to3( buffer ) );
1181                        position = 0;
1182                    } // end if: enough to output
1183
} // end if: meaningful base64 character
1184
else if( DECODABET[ theByte & 0x7f ] != WHITE_SPACE_ENC )
1185                {
1186                    throw new java.io.IOException JavaDoc( "Invalid character in Base64 data." );
1187                } // end else: not white space either
1188
} // end else: decoding
1189
} // end write
1190

1191        
1192        
1193        /**
1194         * Calls {@link #write} repeatedly until <var>len</var>
1195         * bytes are written.
1196         *
1197         * @param theBytes array from which to read bytes
1198         * @param off offset for array
1199         * @param len max number of bytes to read into array
1200         * @since 1.3
1201         */

1202        public void write( byte[] theBytes, int off, int len ) throws java.io.IOException JavaDoc
1203        {
1204            for( int i = 0; i < len; i++ )
1205            {
1206                write( theBytes[ off + i ] );
1207            } // end for: each byte written
1208

1209        } // end write
1210

1211        
1212        /**
1213         * Appropriately pads Base64 notation when encoding
1214         * or throws an exception if Base64 input is not
1215         * properly padded when decoding.
1216         *
1217         * @since 1.3
1218         */

1219        public void flush() throws java.io.IOException JavaDoc
1220        {
1221            super.flush();
1222            
1223            if( position > 0 )
1224            {
1225                if( encode )
1226                {
1227                    out.write( Base64.encode3to4( buffer, position ) );
1228                } // end if: encoding
1229
else
1230                {
1231                    throw new java.io.IOException JavaDoc( "Base64 input not properly padded." );
1232                } // end else: decoding
1233
} // end if: buffer partially full
1234

1235            out.flush();
1236        } // end flush
1237

1238        
1239        /**
1240         * Flushes and closes stream.
1241         *
1242         * @since 1.3
1243         */

1244        public void close() throws java.io.IOException JavaDoc
1245        {
1246            super.close();
1247            //this.flush();
1248

1249            out.close();
1250            
1251            buffer = null;
1252            out = null;
1253        } // end close
1254

1255    } // end inner class OutputStream
1256

1257    
1258} // end class Base64
1259
Popular Tags