1 package util;
2
3 /***
4 * Encodes and decodes to and from Base64 notation.
5 *
6 * <p>
7 * Change Log:
8 * </p>
9 * <ul>
10 * <li>v1.3.6 - Fixed OutputStream.flush() so that 'position' is reset.</li>
11 * <li>v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream
12 * where last buffer being read, if not completely full, was not returned.</li>
13 * <li>v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.</li>
14 * <li>v1.3.3 - Fixed I/O streams which were totally messed up.</li>
15 * </ul>
16 *
17 * <p>
18 * I am placing this code in the Public Domain. Do with it as you will.
19 * This software comes with no guarantees or warranties but with
20 * plenty of well-wishing instead!
21 * Please visit <a href="http://iharder.net/xmlizable">http://iharder.net/xmlizable</a>
22 * periodically to check for updates or to contribute improvements.
23 * </p>
24 *
25 * @author Robert Harder
26 * @author rob@iharder.net
27 * @version 1.3.4
28 */
29 public class Base64
30 {
31
32 /*** Specify encoding (value is <tt>true</tt>). */
33 public final static boolean ENCODE = true;
34
35
36 /*** Specify decoding (value is <tt>false</tt>). */
37 public final static boolean DECODE = false;
38
39
40 /*** Maximum line length (76) of Base64 output. */
41 private final static int MAX_LINE_LENGTH = 76;
42
43
44 /*** The equals sign (=) as a byte. */
45 private final static byte EQUALS_SIGN = (byte)'=';
46
47
48 /*** The new line character (\n) as a byte. */
49 private final static byte NEW_LINE = (byte)'\n';
50
51
52 /*** The 64 valid Base64 values. */
53 private final static byte[] ALPHABET =
54 {
55 (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
56 (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
57 (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
58 (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
59 (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
60 (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
61 (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
62 (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
63 (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5',
64 (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/'
65 };
66
67 /***
68 * Translates a Base64 value to either its 6-bit reconstruction value
69 * or a negative number indicating some other meaning.
70 **/
71 private final static byte[] DECODABET =
72 {
73 -9,-9,-9,-9,-9,-9,-9,-9,-9,
74 -5,-5,
75 -9,-9,
76 -5,
77 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,
78 -9,-9,-9,-9,-9,
79 -5,
80 -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,
81 62,
82 -9,-9,-9,
83 63,
84 52,53,54,55,56,57,58,59,60,61,
85 -9,-9,-9,
86 -1,
87 -9,-9,-9,
88 0,1,2,3,4,5,6,7,8,9,10,11,12,13,
89 14,15,16,17,18,19,20,21,22,23,24,25,
90 -9,-9,-9,-9,-9,-9,
91 26,27,28,29,30,31,32,33,34,35,36,37,38,
92 39,40,41,42,43,44,45,46,47,48,49,50,51,
93 -9,-9,-9,-9
94
95
96
97
98
99
100
101
102
103
104 };
105
106 private final static byte BAD_ENCODING = -9;
107 private final static byte WHITE_SPACE_ENC = -5;
108 private final static byte EQUALS_SIGN_ENC = -1;
109
110
111 /*** Defeats instantiation. */
112 private Base64(){}
113
114
115
116 /***
117 * Testing. Feel free--in fact I encourage you--to throw out
118 * this entire "main" method when you actually deploy this code.
119 */
120 public static void main( String[] args )
121 {
122 try
123 {
124
125 {
126 byte[] bytes1 = { (byte)2,(byte)2,(byte)3,(byte)0,(byte)9 };
127 byte[] bytes2 = { (byte)99,(byte)2,(byte)2,(byte)3,(byte)0,(byte)9 };
128 System.out.println( "Bytes 2,2,3,0,9 as Base64: " + encodeBytes( bytes1 ) );
129 System.out.println( "Bytes 2,2,3,0,9 w/ offset: " + encodeBytes( bytes2, 1, bytes2.length-1 ) );
130 byte[] dbytes = decode( encodeBytes( bytes1 ) );
131 System.out.print( encodeBytes( bytes1 ) + " decoded: " );
132 for( int i = 0; i < dbytes.length; i++ )
133 System.out.print( dbytes[i] + (i<dbytes.length-1?",":"\n") );
134 }
135
136
137
138
139
140 {
141
142 java.io.FileInputStream fis = new java.io.FileInputStream( "test.gif.b64" );
143 Base64.InputStream b64is = new Base64.InputStream( fis, DECODE );
144
145 byte[] bytes = new byte[0];
146 int b = -1;
147 while( (b = b64is.read()) >= 0 ){
148 byte[] temp = new byte[ bytes.length + 1 ];
149 System.arraycopy( bytes,0, temp,0,bytes.length );
150 temp[bytes.length] = (byte)b;
151 bytes = temp;
152 }
153 b64is.close();
154 javax.swing.ImageIcon iicon = new javax.swing.ImageIcon( bytes );
155 javax.swing.JLabel jlabel = new javax.swing.JLabel( "Read from test.gif.b64", iicon,0 );
156 javax.swing.JFrame jframe = new javax.swing.JFrame();
157 jframe.getContentPane().add( jlabel );
158 jframe.pack();
159 jframe.show();
160
161
162 java.io.FileOutputStream fos = new java.io.FileOutputStream( "test.gif_out" );
163 fos.write( bytes );
164 fos.close();
165
166
167 fis = new java.io.FileInputStream( "test.gif_out" );
168 b64is = new Base64.InputStream( fis, ENCODE );
169 byte[] ebytes = new byte[0];
170 b = -1;
171 while( (b = b64is.read()) >= 0 ){
172 byte[] temp = new byte[ ebytes.length + 1 ];
173 System.arraycopy( ebytes,0, temp,0,ebytes.length );
174 temp[ebytes.length] = (byte)b;
175 ebytes = temp;
176 }
177 b64is.close();
178 String s = new String( ebytes );
179 javax.swing.JTextArea jta = new javax.swing.JTextArea( s );
180 javax.swing.JScrollPane jsp = new javax.swing.JScrollPane( jta );
181 jframe = new javax.swing.JFrame();
182 jframe.setTitle( "Read from test.gif_out" );
183 jframe.getContentPane().add( jsp );
184 jframe.pack();
185 jframe.show();
186
187
188 fos = new java.io.FileOutputStream( "test.gif.b64_out" );
189 fos.write( ebytes );
190
191
192 fis = new java.io.FileInputStream( "test.gif.b64_out" );
193 b64is = new Base64.InputStream( fis, DECODE );
194 byte[] edbytes = new byte[0];
195 b = -1;
196 while( (b = b64is.read()) >= 0 ){
197 byte[] temp = new byte[ edbytes.length + 1 ];
198 System.arraycopy( edbytes,0, temp,0,edbytes.length );
199 temp[edbytes.length] = (byte)b;
200 edbytes = temp;
201 }
202 b64is.close();
203 iicon = new javax.swing.ImageIcon( edbytes );
204 jlabel = new javax.swing.JLabel( "Read from test.gif.b64_out", iicon,0 );
205 jframe = new javax.swing.JFrame();
206 jframe.getContentPane().add( jlabel );
207 jframe.pack();
208 jframe.show();
209 }
210
211
212
213 {
214
215 java.io.FileInputStream fis = new java.io.FileInputStream( "test.gif_out" );
216 byte[] rbytes = new byte[0];
217 int b = -1;
218 while( (b = fis.read()) >= 0 ){
219 byte[] temp = new byte[ rbytes.length + 1 ];
220 System.arraycopy( rbytes,0, temp,0,rbytes.length );
221 temp[rbytes.length] = (byte)b;
222 rbytes = temp;
223 }
224 fis.close();
225
226
227 java.io.FileOutputStream fos = new java.io.FileOutputStream("test.gif.b64_out2");
228 Base64.OutputStream b64os = new Base64.OutputStream( fos, ENCODE );
229 b64os.write( rbytes );
230 b64os.close();
231
232
233
234 fis = new java.io.FileInputStream( "test.gif.b64_out2" );
235 byte[] rebytes = new byte[0];
236 b = -1;
237 while( (b = fis.read()) >= 0 ){
238 byte[] temp = new byte[ rebytes.length + 1 ];
239 System.arraycopy( rebytes,0, temp,0,rebytes.length );
240 temp[rebytes.length] = (byte)b;
241 rebytes = temp;
242 }
243 fis.close();
244 String s = new String( rebytes );
245 javax.swing.JTextArea jta = new javax.swing.JTextArea( s );
246 javax.swing.JScrollPane jsp = new javax.swing.JScrollPane( jta );
247 javax.swing.JFrame jframe = new javax.swing.JFrame();
248 jframe.setTitle( "Read from test.gif.b64_out2" );
249 jframe.getContentPane().add( jsp );
250 jframe.pack();
251 jframe.show();
252
253
254 fos = new java.io.FileOutputStream("test.gif_out2");
255 b64os = new Base64.OutputStream( fos, DECODE );
256 b64os.write( rebytes );
257 b64os.close();
258 javax.swing.ImageIcon iicon = new javax.swing.ImageIcon( "test.gif_out2" );
259 javax.swing.JLabel jlabel = new javax.swing.JLabel( "Read from test.gif_out2", iicon,0 );
260 jframe = new javax.swing.JFrame();
261 jframe.getContentPane().add( jlabel );
262 jframe.pack();
263 jframe.show();
264
265 }
266
267
268
269 {
270 java.io.FileInputStream fis = new java.io.FileInputStream("D://temp//testencoding.txt");
271 Base64.InputStream b64is = new Base64.InputStream( fis, DECODE );
272 java.io.FileOutputStream fos = new java.io.FileOutputStream("D://temp//file.zip");
273 int b;
274 while( (b=b64is.read()) >= 0 )
275 fos.write( b );
276 fos.close();
277 b64is.close();
278
279 }
280
281 }
282 catch( Exception e)
283 { e.printStackTrace();
284 }
285 }
286
287
288
289
290
291 /***
292 * Encodes the first three bytes of array <var>threeBytes</var>
293 * and returns a four-byte array in Base64 notation.
294 *
295 * @param threeBytes the array to convert
296 * @return four byte array in Base64 notation.
297 * @since 1.3
298 */
299 private static byte[] encode3to4( byte[] threeBytes )
300 { return encode3to4( threeBytes, 3 );
301 }
302
303
304
305 /***
306 * Encodes up to the first three bytes of array <var>threeBytes</var>
307 * and returns a four-byte array in Base64 notation.
308 * The actual number of significant bytes in your array is
309 * given by <var>numSigBytes</var>.
310 * The array <var>threeBytes</var> needs only be as big as
311 * <var>numSigBytes</var>.
312 *
313 * @param threeBytes the array to convert
314 * @param numSigBytes the number of significant bytes in your array
315 * @return four byte array in Base64 notation.
316 * @since 1.3
317 */
318 private static byte[] encode3to4( byte[] threeBytes, int numSigBytes )
319 { byte[] dest = new byte[4];
320 encode3to4( threeBytes, 0, numSigBytes, dest, 0 );
321 return dest;
322 }
323
324
325
326 /***
327 * Encodes up to three bytes of the array <var>source</var>
328 * and writes the resulting four Base64 bytes to <var>destination</var>.
329 * The source and destination arrays can be manipulated
330 * anywhere along their length by specifying
331 * <var>srcOffset</var> and <var>destOffset</var>.
332 * This method does not check to make sure your arrays
333 * are large enough to accomodate <var>srcOffset</var> + 3 for
334 * the <var>source</var> array or <var>destOffset</var> + 4 for
335 * the <var>destination</var> array.
336 * The actual number of significant bytes in your array is
337 * given by <var>numSigBytes</var>.
338 *
339 * @param source the array to convert
340 * @param srcOffset the index where conversion begins
341 * @param numSigBytes the number of significant bytes in your array
342 * @param destination the array to hold the conversion
343 * @param destOffset the index where output will be put
344 * @return the <var>destination</var> array
345 * @since 1.3
346 */
347 private static byte[] encode3to4(
348 byte[] source, int srcOffset, int numSigBytes,
349 byte[] destination, int destOffset )
350 {
351
352
353
354
355
356
357
358
359
360
361
362 int inBuff = ( numSigBytes > 0 ? ((source[ srcOffset ] << 24) >>> 8) : 0 )
363 | ( numSigBytes > 1 ? ((source[ srcOffset + 1 ] << 24) >>> 16) : 0 )
364 | ( numSigBytes > 2 ? ((source[ srcOffset + 2 ] << 24) >>> 24) : 0 );
365
366 switch( numSigBytes )
367 {
368 case 3:
369 destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
370 destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
371 destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ];
372 destination[ destOffset + 3 ] = ALPHABET[ (inBuff ) & 0x3f ];
373 return destination;
374
375 case 2:
376 destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
377 destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
378 destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>> 6) & 0x3f ];
379 destination[ destOffset + 3 ] = EQUALS_SIGN;
380 return destination;
381
382 case 1:
383 destination[ destOffset ] = ALPHABET[ (inBuff >>> 18) ];
384 destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
385 destination[ destOffset + 2 ] = EQUALS_SIGN;
386 destination[ destOffset + 3 ] = EQUALS_SIGN;
387 return destination;
388
389 default:
390 return destination;
391 }
392 }
393
394 /***
395 * Serializes an object and returns the Base64-encoded
396 * version of that serialized object. If the object
397 * cannot be serialized or there is another error,
398 * the method will return <tt>null</tt>.
399 *
400 * @param serializableObject The object to encode
401 * @return The Base64-encoded object
402 * @since 1.4
403 */
404 public static String encodeObject( java.io.Serializable serializableObject )
405 {
406 return encodeObject( serializableObject, true );
407 }
408
409 /***
410 * Serializes an object and returns the Base64-encoded
411 * version of that serialized object. If the object
412 * cannot be serialized or there is another error,
413 * the method will return <tt>null</tt>.
414 *
415 * @param serializableObject The object to encode
416 * @param breakLines Break lines at 80 characters or less.
417 * @return The Base64-encoded object
418 * @since 1.4
419 */
420 public static String encodeObject( java.io.Serializable serializableObject, boolean breakLines )
421 {
422 java.io.ByteArrayOutputStream baos = null;
423 java.io.OutputStream b64os = null;
424 java.io.ObjectOutputStream oos = null;
425
426 try
427 {
428 baos = new java.io.ByteArrayOutputStream();
429 b64os = new Base64.OutputStream( baos, Base64.ENCODE, breakLines );
430 oos = new java.io.ObjectOutputStream( b64os );
431
432 oos.writeObject( serializableObject );
433 }
434 catch( java.io.IOException e )
435 {
436 e.printStackTrace();
437 return null;
438 }
439 finally
440 {
441 try{ oos.close(); } catch( Exception e ){}
442 try{ b64os.close(); } catch( Exception e ){}
443 try{ baos.close(); } catch( Exception e ){}
444 }
445
446 return new String( baos.toByteArray() );
447 }
448
449
450 /***
451 * Encodes a byte array into Base64 notation.
452 * Equivalen to calling
453 * <code>encodeBytes( source, 0, source.length )</code>
454 *
455 * @param source The data to convert
456 * @since 1.4
457 */
458 public static String encodeBytes( byte[] source )
459 {
460 return encodeBytes( source, true );
461 }
462
463 /***
464 * Encodes a byte array into Base64 notation.
465 * Equivalen to calling
466 * <code>encodeBytes( source, 0, source.length )</code>
467 *
468 * @param source The data to convert
469 * @param breakLines Break lines at 80 characters or less.
470 * @since 1.4
471 */
472 public static String encodeBytes( byte[] source, boolean breakLines )
473 {
474 return encodeBytes( source, 0, source.length, breakLines );
475 }
476
477
478 /***
479 * Encodes a byte array into Base64 notation.
480 *
481 * @param source The data to convert
482 * @param off Offset in array where conversion should begin
483 * @param len Length of data to convert
484 * @since 1.4
485 */
486 public static String encodeBytes( byte[] source, int off, int len )
487 {
488 return encodeBytes( source, off, len, true );
489 }
490
491
492 /***
493 * Encodes a byte array into Base64 notation.
494 *
495 * @param source The data to convert
496 * @param off Offset in array where conversion should begin
497 * @param len Length of data to convert
498 * @param breakLines Break lines at 80 characters or less.
499 * @since 1.4
500 */
501 public static String encodeBytes( byte[] source, int off, int len, boolean breakLines )
502 {
503 int len43 = len * 4 / 3;
504 byte[] outBuff = new byte[ ( len43 )
505 + ( (len % 3) > 0 ? 4 : 0 )
506 + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ];
507 int d = 0;
508 int e = 0;
509 int len2 = len - 2;
510 int lineLength = 0;
511 for( ; d < len2; d+=3, e+=4 )
512 {
513 encode3to4( source, d+off, 3, outBuff, e );
514
515 lineLength += 4;
516 if( breakLines && lineLength == MAX_LINE_LENGTH )
517 {
518 outBuff[e+4] = NEW_LINE;
519 e++;
520 lineLength = 0;
521 }
522 }
523
524 if( d < len )
525 {
526 encode3to4( source, d+off, len - d, outBuff, e );
527 e += 4;
528 }
529
530 return new String( outBuff, 0, e );
531 }
532
533
534 /***
535 * Encodes a string in Base64 notation with line breaks
536 * after every 75 Base64 characters.
537 *
538 * @param s the string to encode
539 * @return the encoded string
540 * @since 1.3
541 */
542 public static String encodeString( String s )
543 {
544 return encodeString( s, true );
545 }
546
547 /***
548 * Encodes a string in Base64 notation with line breaks
549 * after every 75 Base64 characters.
550 *
551 * @param s the string to encode
552 * @param breakLines Break lines at 80 characters or less.
553 * @return the encoded string
554 * @since 1.3
555 */
556 public static String encodeString( String s, boolean breakLines )
557 {
558 return encodeBytes( s.getBytes(), breakLines );
559 }
560
561
562
563
564
565
566
567 /***
568 * Decodes the first four bytes of array <var>fourBytes</var>
569 * and returns an array up to three bytes long with the
570 * decoded values.
571 *
572 * @param fourBytes the array with Base64 content
573 * @return array with decoded values
574 * @since 1.3
575 */
576 private static byte[] decode4to3( byte[] fourBytes )
577 {
578 byte[] outBuff1 = new byte[3];
579 int count = decode4to3( fourBytes, 0, outBuff1, 0 );
580 byte[] outBuff2 = new byte[ count ];
581
582 for( int i = 0; i < count; i++ )
583 outBuff2[i] = outBuff1[i];
584
585 return outBuff2;
586 }
587
588
589
590
591 /***
592 * Decodes four bytes from array <var>source</var>
593 * and writes the resulting bytes (up to three of them)
594 * to <var>destination</var>.
595 * The source and destination arrays can be manipulated
596 * anywhere along their length by specifying
597 * <var>srcOffset</var> and <var>destOffset</var>.
598 * This method does not check to make sure your arrays
599 * are large enough to accomodate <var>srcOffset</var> + 4 for
600 * the <var>source</var> array or <var>destOffset</var> + 3 for
601 * the <var>destination</var> array.
602 * This method returns the actual number of bytes that
603 * were converted from the Base64 encoding.
604 *
605 *
606 * @param source the array to convert
607 * @param srcOffset the index where conversion begins
608 * @param destination the array to hold the conversion
609 * @param destOffset the index where output will be put
610 * @return the number of decoded bytes converted
611 * @since 1.3
612 */
613 private static int decode4to3( byte[] source, int srcOffset, byte[] destination, int destOffset )
614 {
615
616 if( source[ srcOffset + 2] == EQUALS_SIGN )
617 {
618
619
620
621 int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )
622 | ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 );
623
624 destination[ destOffset ] = (byte)( outBuff >>> 16 );
625 return 1;
626 }
627
628
629 else if( source[ srcOffset + 3 ] == EQUALS_SIGN )
630 {
631
632
633
634
635 int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )
636 | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
637 | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6 );
638
639 destination[ destOffset ] = (byte)( outBuff >>> 16 );
640 destination[ destOffset + 1 ] = (byte)( outBuff >>> 8 );
641 return 2;
642 }
643
644
645 else
646 {
647 try{
648
649
650
651
652
653 int outBuff = ( ( DECODABET[ source[ srcOffset ] ] & 0xFF ) << 18 )
654 | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
655 | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) << 6)
656 | ( ( DECODABET[ source[ srcOffset + 3 ] ] & 0xFF ) );
657
658
659 destination[ destOffset ] = (byte)( outBuff >> 16 );
660 destination[ destOffset + 1 ] = (byte)( outBuff >> 8 );
661 destination[ destOffset + 2 ] = (byte)( outBuff );
662
663 return 3;
664 }catch( Exception e){
665 System.out.println(""+source[srcOffset]+ ": " + ( DECODABET[ source[ srcOffset ] ] ) );
666 System.out.println(""+source[srcOffset+1]+ ": " + ( DECODABET[ source[ srcOffset + 1 ] ] ) );
667 System.out.println(""+source[srcOffset+2]+ ": " + ( DECODABET[ source[ srcOffset + 2 ] ] ) );
668 System.out.println(""+source[srcOffset+3]+ ": " + ( DECODABET[ source[ srcOffset + 3 ] ] ) );
669 return -1;
670 }
671 }
672 }
673
674
675
676 /***
677 * Decodes data from Base64 notation.
678 *
679 * @param s the string to decode
680 * @return the decoded data
681 * @since 1.4
682 */
683 public static byte[] decode( String s )
684 {
685 byte[] bytes = s.getBytes();
686 return decode( bytes, 0, bytes.length );
687 }
688
689
690 /***
691 * Decodes data from Base64 notation and
692 * returns it as a string.
693 * Equivlaent to calling
694 * <code>new String( decode( s ) )</code>
695 *
696 * @param s the strind to decode
697 * @return The data as a string
698 * @since 1.4
699 */
700 public static String decodeToString( String s )
701 { return new String( decode( s ) );
702 }
703
704
705 /***
706 * Attempts to decode Base64 data and deserialize a Java
707 * Object within. Returns <tt>null if there was an error.
708 *
709 * @param encodedObject The Base64 data to decode
710 * @return The decoded and deserialized object
711 * @since 1.4
712 */
713 public static Object decodeToObject( String encodedObject )
714 {
715 byte[] objBytes = decode( encodedObject );
716
717 java.io.ByteArrayInputStream bais = null;
718 java.io.ObjectInputStream ois = null;
719
720 try
721 {
722 bais = new java.io.ByteArrayInputStream( objBytes );
723 ois = new java.io.ObjectInputStream( bais );
724
725 return ois.readObject();
726 }
727 catch( java.io.IOException e )
728 {
729 e.printStackTrace();
730 return null;
731 }
732 catch( java.lang.ClassNotFoundException e )
733 {
734 e.printStackTrace();
735 return null;
736 }
737 finally
738 {
739 try{ bais.close(); } catch( Exception e ){}
740 try{ ois.close(); } catch( Exception e ){}
741 }
742 }
743
744
745 /***
746 * Decodes Base64 content in byte array format and returns
747 * the decoded byte array.
748 *
749 * @param source The Base64 encoded data
750 * @param off The offset of where to begin decoding
751 * @param len The length of characters to decode
752 * @return decoded data
753 * @since 1.3
754 */
755 public static byte[] decode( byte[] source, int off, int len )
756 {
757 int len34 = len * 3 / 4;
758 byte[] outBuff = new byte[ len34 ];
759 int outBuffPosn = 0;
760
761 byte[] b4 = new byte[4];
762 int b4Posn = 0;
763 int i = 0;
764 byte sbiCrop = 0;
765 byte sbiDecode = 0;
766 for( i = 0; i < len; i++ )
767 {
768 sbiCrop = (byte)(source[i] & 0x7f);
769 sbiDecode = DECODABET[ sbiCrop ];
770
771 if( sbiDecode >= WHITE_SPACE_ENC )
772 {
773 if( sbiDecode >= EQUALS_SIGN_ENC )
774 {
775 b4[ b4Posn++ ] = sbiCrop;
776 if( b4Posn > 3 )
777 {
778 outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn );
779 b4Posn = 0;
780
781
782 if( sbiCrop == EQUALS_SIGN )
783 break;
784 }
785
786 }
787
788 }
789 else
790 {
791 System.err.println( "Bad Base64 input character at " + i + ": " + source[i] + "(decimal)" );
792 return null;
793 }
794 }
795
796 byte[] out = new byte[ outBuffPosn ];
797 System.arraycopy( outBuff, 0, out, 0, outBuffPosn );
798 return out;
799 }
800
801
802
803
804
805
806
807
808 /***
809 * A {@link Base64#InputStream} will read data from another
810 * {@link java.io.InputStream}, given in the constructor,
811 * and encode/decode to/from Base64 notation on the fly.
812 *
813 * @see Base64
814 * @see java.io.FilterInputStream
815 * @since 1.3
816 */
817 public static class InputStream extends java.io.FilterInputStream
818 {
819 private boolean encode;
820 private int position;
821 private byte[] buffer;
822 private int bufferLength;
823 private int numSigBytes;
824 private int lineLength;
825 private boolean breakLines;
826
827
828 /***
829 * Constructs a {@link Base64#InputStream} in DECODE mode.
830 *
831 * @param in the {@link java.io.InputStream} from which to read data.
832 * @since 1.3
833 */
834 public InputStream( java.io.InputStream in )
835 {
836 this( in, Base64.DECODE );
837 }
838
839
840 /***
841 * Constructs a {@link Base64#InputStream} in
842 * either ENCODE or DECODE mode.
843 *
844 * @param in the {@link java.io.InputStream} from which to read data.
845 * @param encode Conversion direction
846 * @see Base64#ENCODE
847 * @see Base64#DECODE
848 * @since 1.3
849 */
850 public InputStream( java.io.InputStream in, boolean encode )
851 {
852 this( in, encode, true );
853 }
854
855
856 /***
857 * Constructs a {@link Base64#InputStream} in
858 * either ENCODE or DECODE mode.
859 *
860 * @param in the {@link java.io.InputStream} from which to read data.
861 * @param encode Conversion direction
862 * @param breakLines Break lines at less than 80 characters.
863 * @see Base64#ENCODE
864 * @see Base64#DECODE
865 * @since 1.3
866 */
867 public InputStream( java.io.InputStream in, boolean encode, boolean breakLines )
868 {
869 super( in );
870 this.breakLines = breakLines;
871 this.encode = encode;
872 this.bufferLength = encode ? 4 : 3;
873 this.buffer = new byte[ bufferLength ];
874 this.position = -1;
875 this.lineLength = 0;
876 }
877
878 /***
879 * Reads enough of the input stream to convert
880 * to/from Base64 and returns the next byte.
881 *
882 * @return next byte
883 * @since 1.3
884 */
885 public int read() throws java.io.IOException
886 {
887
888 if( position < 0 )
889 {
890 if( encode )
891 {
892 byte[] b3 = new byte[3];
893 int numBinaryBytes = 0;
894 for( int i = 0; i < 3; i++ )
895 {
896 try
897 {
898 int b = in.read();
899
900
901 if( b >= 0 )
902 {
903 b3[i] = (byte)b;
904 numBinaryBytes++;
905 }
906
907 }
908 catch( java.io.IOException e )
909 {
910
911 if( i == 0 )
912 throw e;
913
914 }
915 }
916
917 if( numBinaryBytes > 0 )
918 {
919 encode3to4( b3, 0, numBinaryBytes, buffer, 0 );
920 position = 0;
921 numSigBytes = 4;
922 }
923 else
924 {
925 return -1;
926 }
927 }
928
929
930 else
931 {
932 byte[] b4 = new byte[4];
933 int i = 0;
934 for( i = 0; i < 4; i++ )
935 {
936
937 int b = 0;
938 do{ b = in.read(); }
939 while( b >= 0 && DECODABET[ b & 0x7f ] <= WHITE_SPACE_ENC );
940
941 if( b < 0 )
942 break;
943
944 b4[i] = (byte)b;
945 }
946
947 if( i == 4 )
948 {
949 numSigBytes = decode4to3( b4, 0, buffer, 0 );
950 position = 0;
951 }
952 else if( i == 0 ){
953 return -1;
954 }
955 else
956 {
957
958 throw new java.io.IOException( "Improperly padded Base64 input." );
959 }
960
961 }
962 }
963
964
965 if( position >= 0 )
966 {
967
968 if(
969 return -1;
970
971 if( encode && breakLines && lineLength >= MAX_LINE_LENGTH )
972 {
973 lineLength = 0;
974 return '\n';
975 }
976 else
977 {
978 lineLength++;
979
980
981
982 int b = buffer[ position++ ];
983
984 if( position >= bufferLength )
985 position = -1;
986
987 return b & 0xFF;
988
989 }
990 }
991
992
993 else
994 {
995
996 throw new java.io.IOException( "Error in Base64 code reading stream." );
997 }
998 }
999
1000
1001 /***
1002 * Calls {@link #read} repeatedly until the end of stream
1003 * is reached or <var>len</var> bytes are read.
1004 * Returns number of bytes read into array or -1 if
1005 * end of stream is encountered.
1006 *
1007 * @param dest array to hold values
1008 * @param off offset for array
1009 * @param len max number of bytes to read into array
1010 * @return bytes read into array or -1 if end of stream is encountered.
1011 * @since 1.3
1012 */
1013 public int read( byte[] dest, int off, int len ) throws java.io.IOException
1014 {
1015 int i;
1016 int b;
1017 for( i = 0; i < len; i++ )
1018 {
1019 b = read();
1020
1021
1022
1023
1024 if( b >= 0 )
1025 dest[off + i] = (byte)b;
1026 else if( i == 0 )
1027 return -1;
1028 else
1029 break;
1030 }
1031 return i;
1032 }
1033
1034 }
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045 /***
1046 * A {@link Base64#OutputStream} will write data to another
1047 * {@link java.io.OutputStream}, given in the constructor,
1048 * and encode/decode to/from Base64 notation on the fly.
1049 *
1050 * @see Base64
1051 * @see java.io.FilterOutputStream
1052 * @since 1.3
1053 */
1054 public static class OutputStream extends java.io.FilterOutputStream
1055 {
1056 private boolean encode;
1057 private int position;
1058 private byte[] buffer;
1059 private int bufferLength;
1060 private int lineLength;
1061 private boolean breakLines;
1062
1063
1064 /***
1065 * Constructs a {@link Base64#OutputStream} in ENCODE mode.
1066 *
1067 * @param out the {@link java.io.OutputStream} to which data will be written.
1068 * @since 1.3
1069 */
1070 public OutputStream( java.io.OutputStream out )
1071 {
1072 this( out, Base64.ENCODE );
1073 }
1074
1075
1076 /***
1077 * Constructs a {@link Base64#OutputStream} in
1078 * either ENCODE or DECODE mode.
1079 *
1080 * @param out the {@link java.io.OutputStream} to which data will be written.
1081 * @param encode Conversion direction
1082 * @see Base64#ENCODE
1083 * @see Base64#DECODE
1084 * @since 1.3
1085 */
1086 public OutputStream( java.io.OutputStream out, boolean encode )
1087 {
1088 this( out, encode, true );
1089 }
1090
1091
1092 /***
1093 * Constructs a {@link Base64#OutputStream} in
1094 * either ENCODE or DECODE mode.
1095 *
1096 * @param out the {@link java.io.OutputStream} to which data will be written.
1097 * @param encode Conversion direction
1098 * @param breakLines Break lines to be less than 80 characters.
1099 * @see Base64#ENCODE
1100 * @see Base64#DECODE
1101 * @since 1.3
1102 */
1103 public OutputStream( java.io.OutputStream out, boolean encode, boolean breakLines )
1104 {
1105 super( out );
1106 this.breakLines = breakLines;
1107 this.encode = encode;
1108 this.bufferLength = encode ? 3 : 4;
1109 this.buffer = new byte[ bufferLength ];
1110 this.position = 0;
1111 this.lineLength = 0;
1112 }
1113
1114
1115 /***
1116 * Writes the byte to the output stream after
1117 * converting to/from Base64 notation.
1118 * When encoding, bytes are buffered three
1119 * at a time before the output stream actually
1120 * gets a write() call.
1121 * When decoding, bytes are buffered four
1122 * at a time.
1123 *
1124 * @param theByte the byte to write
1125 * @since 1.3
1126 */
1127 public void write(int theByte) throws java.io.IOException
1128 {
1129 if( encode )
1130 {
1131 buffer[ position++ ] = (byte)theByte;
1132 if( position >= bufferLength )
1133 {
1134 out.write( Base64.encode3to4( buffer, bufferLength ) );
1135
1136 lineLength += 4;
1137 if( breakLines && lineLength >= MAX_LINE_LENGTH )
1138 {
1139 out.write( NEW_LINE );
1140 lineLength = 0;
1141 }
1142
1143 position = 0;
1144 }
1145 }
1146
1147
1148 else
1149 {
1150
1151 if( DECODABET[ theByte & 0x7f ] > WHITE_SPACE_ENC )
1152 {
1153 buffer[ position++ ] = (byte)theByte;
1154 if( position >= bufferLength )
1155 {
1156 out.write( Base64.decode4to3( buffer ) );
1157 position = 0;
1158 }
1159 }
1160 else if( DECODABET[ theByte & 0x7f ] != WHITE_SPACE_ENC )
1161 {
1162 throw new java.io.IOException( "Invalid character in Base64 data." );
1163 }
1164 }
1165 }
1166
1167
1168
1169 /***
1170 * Calls {@link #write} repeatedly until <var>len</var>
1171 * bytes are written.
1172 *
1173 * @param theBytes array from which to read bytes
1174 * @param off offset for array
1175 * @param len max number of bytes to read into array
1176 * @since 1.3
1177 */
1178 public void write( byte[] theBytes, int off, int len ) throws java.io.IOException
1179 {
1180 for( int i = 0; i < len; i++ )
1181 {
1182 write( theBytes[ off + i ] );
1183 }
1184
1185 }
1186
1187
1188 /***
1189 * Appropriately pads Base64 notation when encoding
1190 * or throws an exception if Base64 input is not
1191 * properly padded when decoding.
1192 *
1193 * @since 1.3
1194 */
1195 public void flush() throws java.io.IOException
1196 {
1197 super.flush();
1198
1199 if( position > 0 )
1200 {
1201 if( encode )
1202 {
1203 out.write( Base64.encode3to4( buffer, position ) );
1204 position = 0;
1205 }
1206 else
1207 {
1208 throw new java.io.IOException( "Base64 input not properly padded." );
1209 }
1210 }
1211
1212 out.flush();
1213 }
1214
1215
1216 /***
1217 * Flushes and closes (I think, in the superclass) the stream.
1218 *
1219 * @since 1.3
1220 */
1221 public void close() throws java.io.IOException
1222 {
1223 super.close();
1224
1225
1226 out.close();
1227
1228 buffer = null;
1229 out = null;
1230 }
1231
1232 }
1233
1234
1235 }