KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > dbunit > util > Base64


1
2 package org.dbunit.util;
3
4 /**
5  * <p>
6  * I am placing this code in the Public Domain. Do with it as you will.
7  * This software comes with no guarantees or warranties but with
8  * plenty of well-wishing instead!
9  * Please visit <a HREF="http://iharder.net/base64">http://iharder.net/base64</a>
10  * periodically to check for updates or to contribute improvements.
11  * </p>
12  *
13  * @author Robert Harder
14  * @author rharder@usa.net
15  * @version 1.3
16  */

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

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

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

98
99     /** Defeats instantiation. */
100     private Base64()
101     {
102     }
103
104
105     /** Testing. */
106     public static void main(String JavaDoc[] args)
107     {
108         String JavaDoc s = "Hello, world";
109         s = "abcd";
110         //s = System.getProperties().toString();
111
//System.out.println( s + ": \n [" + encode( s ) + "]\n [" + decode(encode(s)) + "]" );
112

113         byte[] b = encodeString(s).getBytes();
114         byte[] c = decode(b, 0, b.length);
115
116         System.out.println("\n\n" + s + ":" + new String JavaDoc(b) + ":" + new String JavaDoc(c));
117
118         try
119         {
120             java.io.FileInputStream JavaDoc fis = new java.io.FileInputStream JavaDoc("c:\\abcd.txt");
121             InputStream b64is = new InputStream(fis, DECODE);
122             int ib = 0;
123             while ((ib = b64is.read()) > 0)
124             { //System.out.print( new String( ""+(char)ib ) );
125
}
126         } // end try
127
catch (Exception JavaDoc e)
128         {
129             e.printStackTrace();
130         }
131     }
132
133
134 /* ******** E N C O D I N G M E T H O D S ******** */
135
136
137     /**
138      * Encodes the first three bytes of array <var>threeBytes</var>
139      * and returns a four-byte array in Base64 notation.
140      *
141      * @param threeBytes the array to convert
142      * @return four byte array in Base64 notation.
143      * @since 1.3
144      */

145     private static byte[] encode3to4(byte[] threeBytes)
146     {
147         return encode3to4(threeBytes, 3);
148     } // end encodeToBytes
149

150
151     /**
152      * Encodes up to the first three bytes of array <var>threeBytes</var>
153      * and returns a four-byte array in Base64 notation.
154      * The actual number of significant bytes in your array is
155      * given by <var>numSigBytes</var>.
156      * The array <var>threeBytes</var> needs only be as big as
157      * <var>numSigBytes</var>.
158      *
159      * @param threeBytes the array to convert
160      * @param numSigBytes the number of significant bytes in your array
161      * @return four byte array in Base64 notation.
162      * @since 1.3
163      */

164     private static byte[] encode3to4(byte[] threeBytes, int numSigBytes)
165     {
166         byte[] dest = new byte[4];
167         encode3to4(threeBytes, 0, numSigBytes, dest, 0);
168         return dest;
169     }
170
171
172     /**
173      * Encodes up to three bytes of the array <var>source</var>
174      * and writes the resulting four Base64 bytes to <var>destination</var>.
175      * The source and destination arrays can be manipulated
176      * anywhere along their length by specifying
177      * <var>srcOffset</var> and <var>destOffset</var>.
178      * This method does not check to make sure your arrays
179      * are large enough to accomodate <var>srcOffset</var> + 3 for
180      * the <var>source</var> array or <var>destOffset</var> + 4 for
181      * the <var>destination</var> array.
182      * The actual number of significant bytes in your array is
183      * given by <var>numSigBytes</var>.
184      *
185      * @param source the array to convert
186      * @param srcOffset the index where conversion begins
187      * @param numSigBytes the number of significant bytes in your array
188      * @param destination the array to hold the conversion
189      * @param destOffset the index where output will be put
190      * @return the <var>destination</var> array
191      * @since 1.3
192      */

193     private static byte[] encode3to4(
194             byte[] source, int srcOffset, int numSigBytes,
195             byte[] destination, int destOffset)
196     {
197         // 1 2 3
198
// 01234567890123456789012345678901 Bit position
199
// --------000000001111111122222222 Array position from threeBytes
200
// --------| || || || | Six bit groups to index ALPHABET
201
// >>18 >>12 >> 6 >> 0 Right shift necessary
202
// 0x3f 0x3f 0x3f Additional AND
203

204         // Create buffer with zero-padding if there are only one or two
205
// significant bytes passed in the array.
206
// We have to shift left 24 in order to flush out the 1's that appear
207
// when Java treats a value as negative that is cast from a byte to an int.
208
int inBuff = (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0)
209                 | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0)
210                 | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0);
211
212         switch (numSigBytes)
213         {
214             case 3:
215                 destination[destOffset] = ALPHABET[(inBuff >>> 18)];
216                 destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
217                 destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
218                 destination[destOffset + 3] = ALPHABET[(inBuff) & 0x3f];
219                 return destination;
220
221             case 2:
222                 destination[destOffset] = ALPHABET[(inBuff >>> 18)];
223                 destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
224                 destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
225                 destination[destOffset + 3] = EQUALS_SIGN;
226                 return destination;
227
228             case 1:
229                 destination[destOffset] = ALPHABET[(inBuff >>> 18)];
230                 destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
231                 destination[destOffset + 2] = EQUALS_SIGN;
232                 destination[destOffset + 3] = EQUALS_SIGN;
233                 return destination;
234
235             default:
236                 return destination;
237         } // end switch
238
} // end encode3to4
239

240
241     /**
242      * Serializes an object and returns the Base64-encoded
243      * version of that serialized object. If the object
244      * cannot be serialized or there is another error,
245      * the method will return <tt>null</tt>.
246      *
247      * @param serializableObject The object to encode
248      * @return The Base64-encoded object
249      * @since 1.4
250      */

251     public static String JavaDoc encodeObject(java.io.Serializable JavaDoc serializableObject)
252     {
253         java.io.ByteArrayOutputStream JavaDoc baos = null;
254         java.io.OutputStream JavaDoc b64os = null;
255         java.io.ObjectOutputStream JavaDoc oos = null;
256
257         try
258         {
259             baos = new java.io.ByteArrayOutputStream JavaDoc();
260             b64os = new OutputStream(baos, Base64.ENCODE);
261             oos = new java.io.ObjectOutputStream JavaDoc(b64os);
262
263             oos.writeObject(serializableObject);
264         } // end try
265
catch (java.io.IOException JavaDoc e)
266         {
267             e.printStackTrace();
268             return null;
269         } // end catch
270
finally
271         {
272             try
273             {
274                 oos.close();
275             }
276             catch (Exception JavaDoc e)
277             {
278             }
279             try
280             {
281                 b64os.close();
282             }
283             catch (Exception JavaDoc e)
284             {
285             }
286             try
287             {
288                 baos.close();
289             }
290             catch (Exception JavaDoc e)
291             {
292             }
293         } // end finally
294

295         return new String JavaDoc(baos.toByteArray());
296     } // end encode
297

298
299     /**
300      * Encodes a byte array into Base64 notation.
301      * Equivalen to calling
302      * <code>encodeBytes( source, 0, source.length )</code>
303      *
304      * @param source The data to convert
305      * @since 1.4
306      */

307     public static String JavaDoc encodeBytes(byte[] source)
308     {
309         return encodeBytes(source, 0, source.length);
310     } // end encodeBytes
311

312
313     /**
314      * Encodes a byte array into Base64 notation.
315      *
316      * @param source The data to convert
317      * @param off Offset in array where conversion should begin
318      * @param len Length of data to convert
319      * @since 1.4
320      */

321     public static String JavaDoc encodeBytes(byte[] source, int off, int len)
322     {
323         int len43 = len * 4 / 3;
324         byte[] outBuff = new byte[(len43) // Main 4:3
325
+ ((len % 3) > 0 ? 4 : 0) // Account for padding
326
+ (len43 / MAX_LINE_LENGTH)]; // New lines
327
int d = 0;
328         int e = 0;
329         int len2 = len - 2;
330         int lineLength = 0;
331         for (; d < len2; d += 3, e += 4)
332         {
333             encode3to4(source, d, 3, outBuff, e);
334
335             lineLength += 4;
336             if (lineLength == MAX_LINE_LENGTH)
337             {
338                 outBuff[e + 4] = NEW_LINE;
339                 e++;
340                 lineLength = 0;
341             } // end if: end of line
342
} // en dfor: each piece of array
343

344         if (d < len)
345         {
346             encode3to4(source, d, len - d, outBuff, e);
347             e += 4;
348         } // end if: some padding needed
349

350         return new String JavaDoc(outBuff, 0, e);
351     } // end encodeBytes
352

353
354     /**
355      * Encodes a string in Base64 notation with line breaks
356      * after every 75 Base64 characters.
357      *
358      * @param s the string to encode
359      * @return the encoded string
360      * @since 1.3
361      */

362     public static String JavaDoc encodeString(String JavaDoc s)
363     {
364         return encodeBytes(s.getBytes());
365     } // end encodeString
366

367
368
369
370 /* ******** D E C O D I N G M E T H O D S ******** */
371
372
373     /**
374      * Decodes the first four bytes of array <var>fourBytes</var>
375      * and returns an array up to three bytes long with the
376      * decoded values.
377      *
378      * @param fourBytes the array with Base64 content
379      * @return array with decoded values
380      * @since 1.3
381      */

382     private static byte[] decode4to3(byte[] fourBytes)
383     {
384         byte[] outBuff1 = new byte[3];
385         int count = decode4to3(fourBytes, 0, outBuff1, 0);
386         byte[] outBuff2 = new byte[count];
387
388         for (int i = 0; i < count; i++)
389             outBuff2[i] = outBuff1[i];
390
391         return outBuff2;
392     }
393
394
395     /**
396      * Decodes four bytes from array <var>source</var>
397      * and writes the resulting bytes (up to three of them)
398      * to <var>destination</var>.
399      * The source and destination arrays can be manipulated
400      * anywhere along their length by specifying
401      * <var>srcOffset</var> and <var>destOffset</var>.
402      * This method does not check to make sure your arrays
403      * are large enough to accomodate <var>srcOffset</var> + 4 for
404      * the <var>source</var> array or <var>destOffset</var> + 3 for
405      * the <var>destination</var> array.
406      * This method returns the actual number of bytes that
407      * were converted from the Base64 encoding.
408      *
409      *
410      * @param source the array to convert
411      * @param srcOffset the index where conversion begins
412      * @param destination the array to hold the conversion
413      * @param destOffset the index where output will be put
414      * @return the number of decoded bytes converted
415      * @since 1.3
416      */

417     private static int decode4to3(byte[] source, int srcOffset, byte[] destination, int destOffset)
418     {
419         // Example: Dk==
420
if (source[srcOffset + 2] == EQUALS_SIGN)
421         {
422             int outBuff = ((DECODABET[source[srcOffset]] << 24) >>> 6)
423                     | ((DECODABET[source[srcOffset + 1]] << 24) >>> 12);
424
425             destination[destOffset] = (byte)(outBuff >>> 16);
426             return 1;
427         }
428
429         // Example: DkL=
430
else if (source[srcOffset + 3] == EQUALS_SIGN)
431         {
432             int outBuff = ((DECODABET[source[srcOffset]] << 24) >>> 6)
433                     | ((DECODABET[source[srcOffset + 1]] << 24) >>> 12)
434                     | ((DECODABET[source[srcOffset + 2]] << 24) >>> 18);
435
436             destination[destOffset] = (byte)(outBuff >>> 16);
437             destination[destOffset + 1] = (byte)(outBuff >>> 8);
438             return 2;
439         }
440
441         // Example: DkLE
442
else
443         {
444             int outBuff = ((DECODABET[source[srcOffset]] << 24) >>> 6)
445                     | ((DECODABET[source[srcOffset + 1]] << 24) >>> 12)
446                     | ((DECODABET[source[srcOffset + 2]] << 24) >>> 18)
447                     | ((DECODABET[source[srcOffset + 3]] << 24) >>> 24);
448
449             destination[destOffset] = (byte)(outBuff >> 16);
450             destination[destOffset + 1] = (byte)(outBuff >> 8);
451             destination[destOffset + 2] = (byte)(outBuff);
452             return 3;
453         }
454     } // end decodeToBytes
455

456
457     /**
458      * Decodes data from Base64 notation.
459      *
460      * @param s the string to decode
461      * @return the decoded data
462      * @since 1.4
463      */

464     public static byte[] decode(String JavaDoc s)
465     {
466         byte[] bytes = s.getBytes();
467         return decode(bytes, 0, bytes.length);
468     } // end decode
469

470
471     /**
472      * Decodes data from Base64 notation and
473      * returns it as a string.
474      * Equivlaent to calling
475      * <code>new String( decode( s ) )</code>
476      *
477      * @param s the strind to decode
478      * @return The data as a string
479      * @since 1.4
480      */

481     public static String JavaDoc decodeToString(String JavaDoc s)
482     {
483         return new String JavaDoc(decode(s));
484     } // end decodeToString
485

486
487     /**
488      * Attempts to decode Base64 data and deserialize a Java
489      * Object within. Returns <tt>null if there was an error.
490      *
491      * @param encodedObject The Base64 data to decode
492      * @return The decoded and deserialized object
493      * @since 1.4
494      */

495     public static Object JavaDoc decodeToObject(String JavaDoc encodedObject)
496     {
497         byte[] objBytes = decode(encodedObject);
498
499         java.io.ByteArrayInputStream JavaDoc bais = null;
500         java.io.ObjectInputStream JavaDoc ois = null;
501
502         try
503         {
504             bais = new java.io.ByteArrayInputStream JavaDoc(objBytes);
505             ois = new java.io.ObjectInputStream JavaDoc(bais);
506
507             return ois.readObject();
508         } // end try
509
catch (java.io.IOException JavaDoc e)
510         {
511             e.printStackTrace();
512             return null;
513         } // end catch
514
catch (ClassNotFoundException JavaDoc e)
515         {
516             e.printStackTrace();
517             return null;
518         } // end catch
519
finally
520         {
521             try
522             {
523                 bais.close();
524             }
525             catch (Exception JavaDoc e)
526             {
527             }
528             try
529             {
530                 ois.close();
531             }
532             catch (Exception JavaDoc e)
533             {
534             }
535         } // end finally
536
} // end decodeObject
537

538
539     /**
540      * Decodes Base64 content in byte array format and returns
541      * the decoded byte array.
542      *
543      * @param source The Base64 encoded data
544      * @param off The offset of where to begin decoding
545      * @param len The length of characters to decode
546      * @return decoded data
547      * @since 1.3
548      */

549     public static byte[] decode(byte[] source, int off, int len)
550     {
551         int len34 = len * 3 / 4;
552         byte[] outBuff = new byte[len34]; // Upper limit on size of output
553
int outBuffPosn = 0;
554
555         byte[] b4 = new byte[4];
556         int b4Posn = 0;
557         int i = 0;
558         byte sbiCrop = 0;
559         byte sbiDecode = 0;
560         for (i = 0; i < len; i++)
561         {
562             sbiCrop = (byte)(source[i] & 0x7f); // Only the low seven bits
563
sbiDecode = DECODABET[sbiCrop];
564
565             if (sbiDecode >= WHITE_SPACE_ENC) // White space, Equals sign or better
566
{
567                 if (sbiDecode >= EQUALS_SIGN_ENC)
568                 {
569                     b4[b4Posn++] = sbiCrop;
570                     if (b4Posn > 3)
571                     {
572                         outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn);
573                         b4Posn = 0;
574
575                         // If that was the equals sign, break out of 'for' loop
576
if (sbiCrop == EQUALS_SIGN)
577                             break;
578                     } // end if: quartet built
579

580                 } // end if: equals sign or better
581

582             } // end if: white space, equals sign or better
583
else
584             {
585                 System.err.println("Bad Base64 input character at " + i + ": " + source[i] + "(decimal)");
586                 return null;
587             } // end else:
588
} // each input character
589

590         byte[] out = new byte[outBuffPosn];
591         System.arraycopy(outBuff, 0, out, 0, outBuffPosn);
592         return out;
593     } // end decode
594

595
596
597
598     /* ******** I N N E R C L A S S I N P U T S T R E A M ******** */
599
600
601
602     /**
603      * A {@link Base64#InputStream} will read data from another
604      * {@link java.io.InputStream}, given in the constructor,
605      * and encode/decode to/from Base64 notation on the fly.
606      *
607      * @see Base64
608      * @see java.io.FilterInputStream
609      * @since 1.3
610      */

611     public static class InputStream extends java.io.FilterInputStream JavaDoc
612     {
613         private boolean encode; // Encoding or decoding
614
private int position; // Current position in the buffer
615
private byte[] buffer; // Small buffer holding converted data
616
private int bufferLength; // Length of buffer (3 or 4)
617
private int numSigBytes; // Number of meaningful bytes in the buffer
618

619
620         /**
621          * Constructs a {@link Base64#InputStream} in DECODE mode.
622          *
623          * @param in the {@link java.io.InputStream} from which to read data.
624          * @since 1.3
625          */

626         public InputStream(java.io.InputStream JavaDoc in)
627         {
628             this(in, Base64.DECODE);
629         } // end constructor
630

631
632         /**
633          * Constructs a {@link Base64#InputStream} in
634          * either ENCODE or DECODE mode.
635          *
636          * @param in the {@link java.io.InputStream} from which to read data.
637          * @param encode Conversion direction
638          * @see Base64#ENCODE
639          * @see Base64#DECODE
640          * @since 1.3
641          */

642         public InputStream(java.io.InputStream JavaDoc in, boolean encode)
643         {
644             super(in);
645             this.encode = encode;
646             this.bufferLength = encode ? 4 : 3;
647             this.buffer = new byte[bufferLength];
648             this.position = -1;
649         } // end constructor
650

651         /**
652          * Reads enough of the input stream to convert
653          * to/from Base64 and returns the next byte.
654          *
655          * @return next byte
656          * @since 1.3
657          */

658         public int read() throws java.io.IOException JavaDoc
659         {
660             // Do we need to get data?
661
if (position < 0)
662             {
663                 if (encode)
664                 {
665                     byte[] b3 = new byte[3];
666                     numSigBytes = 0;
667                     for (int i = 0; i < 3; i++)
668                     {
669                         try
670                         {
671                             int b = in.read();
672
673                             // If end of stream, b is -1.
674
if (b >= 0)
675                             {
676                                 b3[i] = (byte)b;
677                                 numSigBytes++;
678                             } // end if: not end of stream
679

680                         } // end try: read
681
catch (java.io.IOException JavaDoc e)
682                         {
683                             // Only a problem if we got no data at all.
684
if (i == 0)
685                                 throw e;
686
687                         } // end catch
688
} // end for: each needed input byte
689

690                     if (numSigBytes > 0)
691                     {
692                         encode3to4(b3, 0, numSigBytes, buffer, 0);
693                         position = 0;
694                     } // end if: got data
695
} // end if: encoding
696

697                 // Else decoding
698
else
699                 {
700                     byte[] b4 = new byte[4];
701                     int i = 0;
702                     for (i = 0; i < 4; i++)
703                     {
704                         int b = 0;
705                         do
706                         {
707                             b = in.read();
708                         }
709                         while (b >= 0 && DECODABET[b & 0x7f] < WHITE_SPACE_ENC);
710
711                         if (b < 0)
712                             break; // Reads a -1 if end of stream
713

714                         b4[i] = (byte)b;
715                     } // end for: each needed input byte
716

717                     if (i == 4)
718                     {
719                         numSigBytes = decode4to3(b4, 0, buffer, 0);
720                         position = 0;
721                     } // end if: got four characters
722

723                 } // end else: decode
724
} // end else: get data
725

726             // Got data?
727
if (position >= 0)
728             {
729                 // End of relevant data?
730
if (position >= numSigBytes)
731                     return -1;
732
733                 int b = buffer[position++];
734
735                 if (position >= bufferLength)
736                     position = -1;
737
738                 return b;
739             } // end if: position >= 0
740

741             // Else error
742
else
743                 return -1;
744         } // end read
745

746
747         /**
748          * Calls {@link #read} repeatedly until the end of stream
749          * is reached or <var>len</var> bytes are read.
750          * Returns number of bytes read into array or -1 if
751          * end of stream is encountered.
752          *
753          * @param dest array to hold values
754          * @param off offset for array
755          * @param len max number of bytes to read into array
756          * @return bytes read into array or -1 if end of stream is encountered.
757          * @since 1.3
758          */

759         public int read(byte[] dest, int off, int len) throws java.io.IOException JavaDoc
760         {
761             int i;
762             int b;
763             for (i = 0; i < len; i++)
764             {
765                 b = read();
766
767                 if (b < 0)
768                     return -1;
769
770                 dest[off + i] = (byte)b;
771             } // end for: each byte read
772
return i;
773         } // end read
774

775     } // end inner class InputStream
776

777
778
779
780
781
782     /* ******** I N N E R C L A S S O U T P U T S T R E A M ******** */
783
784
785
786     /**
787      * A {@link Base64#OutputStream} will write data to another
788      * {@link java.io.OutputStream}, given in the constructor,
789      * and encode/decode to/from Base64 notation on the fly.
790      *
791      * @see Base64
792      * @see java.io.FilterOutputStream
793      * @since 1.3
794      */

795     public static class OutputStream extends java.io.FilterOutputStream JavaDoc
796     {
797         private boolean encode;
798         private int position;
799         private byte[] buffer;
800         private int bufferLength;
801         private int lineLength;
802
803
804         /**
805          * Constructs a {@link Base64#OutputStream} in ENCODE mode.
806          *
807          * @param out the {@link java.io.OutputStream} to which data will be written.
808          * @since 1.3
809          */

810         public OutputStream(java.io.OutputStream JavaDoc out)
811         {
812             this(out, Base64.ENCODE);
813         } // end constructor
814

815
816         /**
817          * Constructs a {@link Base64#OutputStream} in
818          * either ENCODE or DECODE mode.
819          *
820          * @param out the {@link java.io.OutputStream} to which data will be written.
821          * @param encode Conversion direction
822          * @see Base64#ENCODE
823          * @see Base64#DECODE
824          * @since 1.3
825          */

826         public OutputStream(java.io.OutputStream JavaDoc out, boolean encode)
827         {
828             super(out);
829             this.encode = encode;
830             this.bufferLength = encode ? 3 : 4;
831             this.buffer = new byte[bufferLength];
832             this.position = 0;
833             this.lineLength = 0;
834         } // end constructor
835

836
837         /**
838          * Writes the byte to the output stream after
839          * converting to/from Base64 notation.
840          * When encoding, bytes are buffered three
841          * at a time before the output stream actually
842          * gets a write() call.
843          * When decoding, bytes are buffered four
844          * at a time.
845          *
846          * @param theByte the byte to write
847          * @since 1.3
848          */

849         public void write(int theByte) throws java.io.IOException JavaDoc
850         {
851             buffer[position++] = (byte)theByte;
852             if (position >= bufferLength)
853             {
854                 if (encode)
855                 {
856                     out.write(Base64.encode3to4(buffer, bufferLength));
857
858                     lineLength += 4;
859                     if (lineLength >= MAX_LINE_LENGTH)
860                     {
861                         out.write(NEW_LINE);
862                         lineLength = 0;
863                     } // end if: end o fline
864
} // end if: encoding
865
else
866                     out.write(Base64.decode4to3(buffer));
867
868                 position = 0;
869             } // end if: convert and flush
870
} // end write
871

872
873         /**
874          * Calls {@link #write} repeatedly until <var>len</var>
875          * bytes are written.
876          *
877          * @param theBytes array from which to read bytes
878          * @param off offset for array
879          * @param len max number of bytes to read into array
880          * @since 1.3
881          */

882         public void write(byte[] theBytes, int off, int len) throws java.io.IOException JavaDoc
883         {
884             for (int i = 0; i < len; i++)
885             {
886                 write(theBytes[off + i]);
887             } // end for: each byte written
888

889         } // end write
890

891
892         /**
893          * Appropriately pads Base64 notation when encoding
894          * or throws an exception if Base64 input is not
895          * properly padded when decoding.
896          *
897          * @since 1.3
898          */

899         public void flush() throws java.io.IOException JavaDoc
900         {
901             if (position > 0)
902             {
903                 if (encode)
904                 {
905                     out.write(Base64.encode3to4(buffer, position));
906                 } // end if: encoding
907
else
908                 {
909                     throw new java.io.IOException JavaDoc("Base64 input not properly padded.");
910                 } // end else: decoding
911
} // end if: buffer partially full
912

913             super.flush();
914             out.flush();
915         } // end flush
916

917
918         /**
919          * Flushes and closes stream.
920          *
921          * @since 1.3
922          */

923         public void close() throws java.io.IOException JavaDoc
924         {
925             this.flush();
926
927             super.close();
928             out.close();
929
930             buffer = null;
931             out = null;
932         } // end close
933

934     } // end inner class OutputStream
935

936
937 } // end class Base64
938

939
940
941
Popular Tags