• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * $RCSfile$
3  * $Revision$
4  * $Date$
5  *
6  */
7 package org.jivesoftware.smack.util;
8 
9 /**
10  * <p>Encodes and decodes to and from Base64 notation.</p>
11  * This code was obtained from <a href="http://iharder.net/base64">http://iharder.net/base64</a></p>
12  *
13  *
14  * @author Robert Harder
15  * @author rob@iharder.net
16  * @version 2.2.1
17  */
18 public class Base64
19 {
20 
21 /* ********  P U B L I C   F I E L D S  ******** */
22 
23 
24     /** No options specified. Value is zero. */
25     public final static int NO_OPTIONS = 0;
26 
27     /** Specify encoding. */
28     public final static int ENCODE = 1;
29 
30 
31     /** Specify decoding. */
32     public final static int DECODE = 0;
33 
34 
35     /** Specify that data should be gzip-compressed. */
36     public final static int GZIP = 2;
37 
38 
39     /** Don't break lines when encoding (violates strict Base64 specification) */
40     public final static int DONT_BREAK_LINES = 8;
41 
42 	/**
43 	 * Encode using Base64-like encoding that is URL- and Filename-safe as described
44 	 * in Section 4 of RFC3548:
45 	 * <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
46 	 * It is important to note that data encoded this way is <em>not</em> officially valid Base64,
47 	 * or at the very least should not be called Base64 without also specifying that is
48 	 * was encoded using the URL- and Filename-safe dialect.
49 	 */
50 	 public final static int URL_SAFE = 16;
51 
52 
53 	 /**
54 	  * Encode using the special "ordered" dialect of Base64 described here:
55 	  * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
56 	  */
57 	 public final static int ORDERED = 32;
58 
59 
60 /* ********  P R I V A T E   F I E L D S  ******** */
61 
62 
63     /** Maximum line length (76) of Base64 output. */
64     private final static int MAX_LINE_LENGTH = 76;
65 
66 
67     /** The equals sign (=) as a byte. */
68     private final static byte EQUALS_SIGN = (byte)'=';
69 
70 
71     /** The new line character (\n) as a byte. */
72     private final static byte NEW_LINE = (byte)'\n';
73 
74 
75     /** Preferred encoding. */
76     private final static String PREFERRED_ENCODING = "UTF-8";
77 
78 
79     // I think I end up not using the BAD_ENCODING indicator.
80     //private final static byte BAD_ENCODING    = -9; // Indicates error in encoding
81     private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding
82     private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding
83 
84 
85 /* ********  S T A N D A R D   B A S E 6 4   A L P H A B E T  ******** */
86 
87     /** The 64 valid Base64 values. */
88     //private final static byte[] ALPHABET;
89 	/* Host platform me be something funny like EBCDIC, so we hardcode these values. */
90 	private final static byte[] _STANDARD_ALPHABET =
91     {
92         (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
93         (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
94         (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
95         (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
96         (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
97         (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
98         (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
99         (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
100         (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5',
101         (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/'
102     };
103 
104 
105     /**
106      * Translates a Base64 value to either its 6-bit reconstruction value
107      * or a negative number indicating some other meaning.
108      **/
109     private final static byte[] _STANDARD_DECODABET =
110     {
111         -9,-9,-9,-9,-9,-9,-9,-9,-9,                 // Decimal  0 -  8
112         -5,-5,                                      // Whitespace: Tab and Linefeed
113         -9,-9,                                      // Decimal 11 - 12
114         -5,                                         // Whitespace: Carriage Return
115         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 14 - 26
116         -9,-9,-9,-9,-9,                             // Decimal 27 - 31
117         -5,                                         // Whitespace: Space
118         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,              // Decimal 33 - 42
119         62,                                         // Plus sign at decimal 43
120         -9,-9,-9,                                   // Decimal 44 - 46
121         63,                                         // Slash at decimal 47
122         52,53,54,55,56,57,58,59,60,61,              // Numbers zero through nine
123         -9,-9,-9,                                   // Decimal 58 - 60
124         -1,                                         // Equals sign at decimal 61
125         -9,-9,-9,                                      // Decimal 62 - 64
126         0,1,2,3,4,5,6,7,8,9,10,11,12,13,            // Letters 'A' through 'N'
127         14,15,16,17,18,19,20,21,22,23,24,25,        // Letters 'O' through 'Z'
128         -9,-9,-9,-9,-9,-9,                          // Decimal 91 - 96
129         26,27,28,29,30,31,32,33,34,35,36,37,38,     // Letters 'a' through 'm'
130         39,40,41,42,43,44,45,46,47,48,49,50,51,     // Letters 'n' through 'z'
131         -9,-9,-9,-9                                 // Decimal 123 - 126
132         /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 127 - 139
133         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 140 - 152
134         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 153 - 165
135         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 166 - 178
136         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 179 - 191
137         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 192 - 204
138         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 205 - 217
139         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 218 - 230
140         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 231 - 243
141         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9         // Decimal 244 - 255 */
142     };
143 
144 
145 /* ********  U R L   S A F E   B A S E 6 4   A L P H A B E T  ******** */
146 
147 	/**
148 	 * Used in the URL- and Filename-safe dialect described in Section 4 of RFC3548:
149 	 * <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
150 	 * Notice that the last two bytes become "hyphen" and "underscore" instead of "plus" and "slash."
151 	 */
152     private final static byte[] _URL_SAFE_ALPHABET =
153     {
154       (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
155       (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
156       (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
157       (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
158       (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
159       (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
160       (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
161       (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
162       (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5',
163       (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'-', (byte)'_'
164     };
165 
166 	/**
167 	 * Used in decoding URL- and Filename-safe dialects of Base64.
168 	 */
169     private final static byte[] _URL_SAFE_DECODABET =
170     {
171       -9,-9,-9,-9,-9,-9,-9,-9,-9,                 // Decimal  0 -  8
172       -5,-5,                                      // Whitespace: Tab and Linefeed
173       -9,-9,                                      // Decimal 11 - 12
174       -5,                                         // Whitespace: Carriage Return
175       -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 14 - 26
176       -9,-9,-9,-9,-9,                             // Decimal 27 - 31
177       -5,                                         // Whitespace: Space
178       -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,              // Decimal 33 - 42
179       -9,                                         // Plus sign at decimal 43
180       -9,                                         // Decimal 44
181       62,                                         // Minus sign at decimal 45
182       -9,                                         // Decimal 46
183       -9,                                         // Slash at decimal 47
184       52,53,54,55,56,57,58,59,60,61,              // Numbers zero through nine
185       -9,-9,-9,                                   // Decimal 58 - 60
186       -1,                                         // Equals sign at decimal 61
187       -9,-9,-9,                                   // Decimal 62 - 64
188       0,1,2,3,4,5,6,7,8,9,10,11,12,13,            // Letters 'A' through 'N'
189       14,15,16,17,18,19,20,21,22,23,24,25,        // Letters 'O' through 'Z'
190       -9,-9,-9,-9,                                // Decimal 91 - 94
191       63,                                         // Underscore at decimal 95
192       -9,                                         // Decimal 96
193       26,27,28,29,30,31,32,33,34,35,36,37,38,     // Letters 'a' through 'm'
194       39,40,41,42,43,44,45,46,47,48,49,50,51,     // Letters 'n' through 'z'
195       -9,-9,-9,-9                                 // Decimal 123 - 126
196       /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 127 - 139
197       -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 140 - 152
198       -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 153 - 165
199       -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 166 - 178
200       -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 179 - 191
201       -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 192 - 204
202       -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 205 - 217
203       -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 218 - 230
204       -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 231 - 243
205       -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9         // Decimal 244 - 255 */
206     };
207 
208 
209 
210 /* ********  O R D E R E D   B A S E 6 4   A L P H A B E T  ******** */
211 
212 	/**
213 	 * I don't get the point of this technique, but it is described here:
214 	 * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
215 	 */
216     private final static byte[] _ORDERED_ALPHABET =
217     {
218       (byte)'-',
219       (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4',
220       (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9',
221       (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
222       (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
223       (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
224       (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
225       (byte)'_',
226       (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
227       (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
228       (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
229       (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z'
230     };
231 
232 	/**
233 	 * Used in decoding the "ordered" dialect of Base64.
234 	 */
235     private final static byte[] _ORDERED_DECODABET =
236     {
237       -9,-9,-9,-9,-9,-9,-9,-9,-9,                 // Decimal  0 -  8
238       -5,-5,                                      // Whitespace: Tab and Linefeed
239       -9,-9,                                      // Decimal 11 - 12
240       -5,                                         // Whitespace: Carriage Return
241       -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 14 - 26
242       -9,-9,-9,-9,-9,                             // Decimal 27 - 31
243       -5,                                         // Whitespace: Space
244       -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,              // Decimal 33 - 42
245       -9,                                         // Plus sign at decimal 43
246       -9,                                         // Decimal 44
247       0,                                          // Minus sign at decimal 45
248       -9,                                         // Decimal 46
249       -9,                                         // Slash at decimal 47
250       1,2,3,4,5,6,7,8,9,10,                       // Numbers zero through nine
251       -9,-9,-9,                                   // Decimal 58 - 60
252       -1,                                         // Equals sign at decimal 61
253       -9,-9,-9,                                   // Decimal 62 - 64
254       11,12,13,14,15,16,17,18,19,20,21,22,23,     // Letters 'A' through 'M'
255       24,25,26,27,28,29,30,31,32,33,34,35,36,     // Letters 'N' through 'Z'
256       -9,-9,-9,-9,                                // Decimal 91 - 94
257       37,                                         // Underscore at decimal 95
258       -9,                                         // Decimal 96
259       38,39,40,41,42,43,44,45,46,47,48,49,50,     // Letters 'a' through 'm'
260       51,52,53,54,55,56,57,58,59,60,61,62,63,     // Letters 'n' through 'z'
261       -9,-9,-9,-9                                 // Decimal 123 - 126
262       /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 127 - 139
263         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 140 - 152
264         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 153 - 165
265         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 166 - 178
266         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 179 - 191
267         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 192 - 204
268         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 205 - 217
269         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 218 - 230
270         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 231 - 243
271         -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9         // Decimal 244 - 255 */
272     };
273 
274 
275 /* ********  D E T E R M I N E   W H I C H   A L H A B E T  ******** */
276 
277 
278 	/**
279 	 * Returns one of the _SOMETHING_ALPHABET byte arrays depending on
280 	 * the options specified.
281 	 * It's possible, though silly, to specify ORDERED and URLSAFE
282 	 * in which case one of them will be picked, though there is
283 	 * no guarantee as to which one will be picked.
284 	 */
getAlphabet( int options )285 	private final static byte[] getAlphabet( int options )
286 	{
287 		if( (options & URL_SAFE) == URL_SAFE ) return _URL_SAFE_ALPHABET;
288 		else if( (options & ORDERED) == ORDERED ) return _ORDERED_ALPHABET;
289 		else return _STANDARD_ALPHABET;
290 
291 	}	// end getAlphabet
292 
293 
294 	/**
295 	 * Returns one of the _SOMETHING_DECODABET byte arrays depending on
296 	 * the options specified.
297 	 * It's possible, though silly, to specify ORDERED and URL_SAFE
298 	 * in which case one of them will be picked, though there is
299 	 * no guarantee as to which one will be picked.
300 	 */
getDecodabet( int options )301 	private final static byte[] getDecodabet( int options )
302 	{
303 		if( (options & URL_SAFE) == URL_SAFE ) return _URL_SAFE_DECODABET;
304 		else if( (options & ORDERED) == ORDERED ) return _ORDERED_DECODABET;
305 		else return _STANDARD_DECODABET;
306 
307 	}	// end getAlphabet
308 
309 
310 
311     /** Defeats instantiation. */
Base64()312     private Base64(){}
313 
314     /**
315      * Prints command line usage.
316      *
317      * @param msg A message to include with usage info.
318      */
usage( String msg )319     private final static void usage( String msg )
320     {
321         System.err.println( msg );
322         System.err.println( "Usage: java Base64 -e|-d inputfile outputfile" );
323     }   // end usage
324 
325 
326 /* ********  E N C O D I N G   M E T H O D S  ******** */
327 
328 
329     /**
330      * Encodes up to the first three bytes of array <var>threeBytes</var>
331      * and returns a four-byte array in Base64 notation.
332      * The actual number of significant bytes in your array is
333      * given by <var>numSigBytes</var>.
334      * The array <var>threeBytes</var> needs only be as big as
335      * <var>numSigBytes</var>.
336      * Code can reuse a byte array by passing a four-byte array as <var>b4</var>.
337      *
338      * @param b4 A reusable byte array to reduce array instantiation
339      * @param threeBytes the array to convert
340      * @param numSigBytes the number of significant bytes in your array
341      * @return four byte array in Base64 notation.
342      * @since 1.5.1
343      */
encode3to4( byte[] b4, byte[] threeBytes, int numSigBytes, int options )344     private static byte[] encode3to4( byte[] b4, byte[] threeBytes, int numSigBytes, int options )
345     {
346         encode3to4( threeBytes, 0, numSigBytes, b4, 0, options );
347         return b4;
348     }   // end encode3to4
349 
350 
351     /**
352      * <p>Encodes up to three bytes of the array <var>source</var>
353      * and writes the resulting four Base64 bytes to <var>destination</var>.
354      * The source and destination arrays can be manipulated
355      * anywhere along their length by specifying
356      * <var>srcOffset</var> and <var>destOffset</var>.
357      * This method does not check to make sure your arrays
358      * are large enough to accomodate <var>srcOffset</var> + 3 for
359      * the <var>source</var> array or <var>destOffset</var> + 4 for
360      * the <var>destination</var> array.
361      * The actual number of significant bytes in your array is
362      * given by <var>numSigBytes</var>.</p>
363 	 * <p>This is the lowest level of the encoding methods with
364 	 * all possible parameters.</p>
365      *
366      * @param source the array to convert
367      * @param srcOffset the index where conversion begins
368      * @param numSigBytes the number of significant bytes in your array
369      * @param destination the array to hold the conversion
370      * @param destOffset the index where output will be put
371      * @return the <var>destination</var> array
372      * @since 1.3
373      */
encode3to4( byte[] source, int srcOffset, int numSigBytes, byte[] destination, int destOffset, int options )374     private static byte[] encode3to4(
375      byte[] source, int srcOffset, int numSigBytes,
376      byte[] destination, int destOffset, int options )
377     {
378 		byte[] ALPHABET = getAlphabet( options );
379 
380         //           1         2         3
381         // 01234567890123456789012345678901 Bit position
382         // --------000000001111111122222222 Array position from threeBytes
383         // --------|    ||    ||    ||    | Six bit groups to index ALPHABET
384         //          >>18  >>12  >> 6  >> 0  Right shift necessary
385         //                0x3f  0x3f  0x3f  Additional AND
386 
387         // Create buffer with zero-padding if there are only one or two
388         // significant bytes passed in the array.
389         // We have to shift left 24 in order to flush out the 1's that appear
390         // when Java treats a value as negative that is cast from a byte to an int.
391         int inBuff =   ( numSigBytes > 0 ? ((source[ srcOffset     ] << 24) >>>  8) : 0 )
392                      | ( numSigBytes > 1 ? ((source[ srcOffset + 1 ] << 24) >>> 16) : 0 )
393                      | ( numSigBytes > 2 ? ((source[ srcOffset + 2 ] << 24) >>> 24) : 0 );
394 
395         switch( numSigBytes )
396         {
397             case 3:
398                 destination[ destOffset     ] = ALPHABET[ (inBuff >>> 18)        ];
399                 destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
400                 destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>>  6) & 0x3f ];
401                 destination[ destOffset + 3 ] = ALPHABET[ (inBuff       ) & 0x3f ];
402                 return destination;
403 
404             case 2:
405                 destination[ destOffset     ] = ALPHABET[ (inBuff >>> 18)        ];
406                 destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
407                 destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>>  6) & 0x3f ];
408                 destination[ destOffset + 3 ] = EQUALS_SIGN;
409                 return destination;
410 
411             case 1:
412                 destination[ destOffset     ] = ALPHABET[ (inBuff >>> 18)        ];
413                 destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
414                 destination[ destOffset + 2 ] = EQUALS_SIGN;
415                 destination[ destOffset + 3 ] = EQUALS_SIGN;
416                 return destination;
417 
418             default:
419                 return destination;
420         }   // end switch
421     }   // end encode3to4
422 
423 
424 
425     /**
426      * Serializes an object and returns the Base64-encoded
427      * version of that serialized object. If the object
428      * cannot be serialized or there is another error,
429      * the method will return <tt>null</tt>.
430      * The object is not GZip-compressed before being encoded.
431      *
432      * @param serializableObject The object to encode
433      * @return The Base64-encoded object
434      * @since 1.4
435      */
encodeObject( java.io.Serializable serializableObject )436     public static String encodeObject( java.io.Serializable serializableObject )
437     {
438         return encodeObject( serializableObject, NO_OPTIONS );
439     }   // end encodeObject
440 
441 
442 
443     /**
444      * Serializes an object and returns the Base64-encoded
445      * version of that serialized object. If the object
446      * cannot be serialized or there is another error,
447      * the method will return <tt>null</tt>.
448      * <p>
449      * Valid options:<pre>
450      *   GZIP: gzip-compresses object before encoding it.
451      *   DONT_BREAK_LINES: don't break lines at 76 characters
452      *     <i>Note: Technically, this makes your encoding non-compliant.</i>
453      * </pre>
454      * <p>
455      * Example: <code>encodeObject( myObj, Base64.GZIP )</code> or
456      * <p>
457      * Example: <code>encodeObject( myObj, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
458      *
459      * @param serializableObject The object to encode
460      * @param options Specified options
461      * @return The Base64-encoded object
462      * @see Base64#GZIP
463      * @see Base64#DONT_BREAK_LINES
464      * @since 2.0
465      */
encodeObject( java.io.Serializable serializableObject, int options )466     public static String encodeObject( java.io.Serializable serializableObject, int options )
467     {
468         // Streams
469         java.io.ByteArrayOutputStream  baos  = null;
470         java.io.OutputStream           b64os = null;
471         java.io.ObjectOutputStream     oos   = null;
472         java.util.zip.GZIPOutputStream gzos  = null;
473 
474         // Isolate options
475         int gzip           = (options & GZIP);
476         int dontBreakLines = (options & DONT_BREAK_LINES);
477 
478         try
479         {
480             // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream
481             baos  = new java.io.ByteArrayOutputStream();
482             b64os = new Base64.OutputStream( baos, ENCODE | options );
483 
484             // GZip?
485             if( gzip == GZIP )
486             {
487                 gzos = new java.util.zip.GZIPOutputStream( b64os );
488                 oos  = new java.io.ObjectOutputStream( gzos );
489             }   // end if: gzip
490             else
491                 oos   = new java.io.ObjectOutputStream( b64os );
492 
493             oos.writeObject( serializableObject );
494         }   // end try
495         catch( java.io.IOException e )
496         {
497             e.printStackTrace();
498             return null;
499         }   // end catch
500         finally
501         {
502             try{ oos.close();   } catch( Exception e ){}
503             try{ gzos.close();  } catch( Exception e ){}
504             try{ b64os.close(); } catch( Exception e ){}
505             try{ baos.close();  } catch( Exception e ){}
506         }   // end finally
507 
508         // Return value according to relevant encoding.
509         try
510         {
511             return new String( baos.toByteArray(), PREFERRED_ENCODING );
512         }   // end try
513         catch (java.io.UnsupportedEncodingException uue)
514         {
515             return new String( baos.toByteArray() );
516         }   // end catch
517 
518     }   // end encode
519 
520 
521 
522     /**
523      * Encodes a byte array into Base64 notation.
524      * Does not GZip-compress data.
525      *
526      * @param source The data to convert
527      * @since 1.4
528      */
encodeBytes( byte[] source )529     public static String encodeBytes( byte[] source )
530     {
531         return encodeBytes( source, 0, source.length, NO_OPTIONS );
532     }   // end encodeBytes
533 
534 
535 
536     /**
537      * Encodes a byte array into Base64 notation.
538      * <p>
539      * Valid options:<pre>
540      *   GZIP: gzip-compresses object before encoding it.
541      *   DONT_BREAK_LINES: don't break lines at 76 characters
542      *     <i>Note: Technically, this makes your encoding non-compliant.</i>
543      * </pre>
544      * <p>
545      * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
546      * <p>
547      * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
548      *
549      *
550      * @param source The data to convert
551      * @param options Specified options
552      * @see Base64#GZIP
553      * @see Base64#DONT_BREAK_LINES
554      * @since 2.0
555      */
encodeBytes( byte[] source, int options )556     public static String encodeBytes( byte[] source, int options )
557     {
558         return encodeBytes( source, 0, source.length, options );
559     }   // end encodeBytes
560 
561 
562     /**
563      * Encodes a byte array into Base64 notation.
564      * Does not GZip-compress data.
565      *
566      * @param source The data to convert
567      * @param off Offset in array where conversion should begin
568      * @param len Length of data to convert
569      * @since 1.4
570      */
encodeBytes( byte[] source, int off, int len )571     public static String encodeBytes( byte[] source, int off, int len )
572     {
573         return encodeBytes( source, off, len, NO_OPTIONS );
574     }   // end encodeBytes
575 
576 
577 
578     /**
579      * Encodes a byte array into Base64 notation.
580      * <p>
581      * Valid options:<pre>
582      *   GZIP: gzip-compresses object before encoding it.
583      *   DONT_BREAK_LINES: don't break lines at 76 characters
584      *     <i>Note: Technically, this makes your encoding non-compliant.</i>
585      * </pre>
586      * <p>
587      * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
588      * <p>
589      * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
590      *
591      *
592      * @param source The data to convert
593      * @param off Offset in array where conversion should begin
594      * @param len Length of data to convert
595      * @param options Specified options; alphabet type is pulled from this (standard, url-safe, ordered)
596      * @see Base64#GZIP
597      * @see Base64#DONT_BREAK_LINES
598      * @since 2.0
599      */
encodeBytes( byte[] source, int off, int len, int options )600     public static String encodeBytes( byte[] source, int off, int len, int options )
601     {
602         // Isolate options
603         int dontBreakLines = ( options & DONT_BREAK_LINES );
604         int gzip           = ( options & GZIP   );
605 
606         // Compress?
607         if( gzip == GZIP )
608         {
609             java.io.ByteArrayOutputStream  baos  = null;
610             java.util.zip.GZIPOutputStream gzos  = null;
611             Base64.OutputStream            b64os = null;
612 
613 
614             try
615             {
616                 // GZip -> Base64 -> ByteArray
617                 baos = new java.io.ByteArrayOutputStream();
618                 b64os = new Base64.OutputStream( baos, ENCODE | options );
619                 gzos  = new java.util.zip.GZIPOutputStream( b64os );
620 
621                 gzos.write( source, off, len );
622                 gzos.close();
623             }   // end try
624             catch( java.io.IOException e )
625             {
626                 e.printStackTrace();
627                 return null;
628             }   // end catch
629             finally
630             {
631                 try{ gzos.close();  } catch( Exception e ){}
632                 try{ b64os.close(); } catch( Exception e ){}
633                 try{ baos.close();  } catch( Exception e ){}
634             }   // end finally
635 
636             // Return value according to relevant encoding.
637             try
638             {
639                 return new String( baos.toByteArray(), PREFERRED_ENCODING );
640             }   // end try
641             catch (java.io.UnsupportedEncodingException uue)
642             {
643                 return new String( baos.toByteArray() );
644             }   // end catch
645         }   // end if: compress
646 
647         // Else, don't compress. Better not to use streams at all then.
648         else
649         {
650             // Convert option to boolean in way that code likes it.
651             boolean breakLines = dontBreakLines == 0;
652 
653             int    len43   = len * 4 / 3;
654             byte[] outBuff = new byte[   ( len43 )                      // Main 4:3
655                                        + ( (len % 3) > 0 ? 4 : 0 )      // Account for padding
656                                        + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines
657             int d = 0;
658             int e = 0;
659             int len2 = len - 2;
660             int lineLength = 0;
661             for( ; d < len2; d+=3, e+=4 )
662             {
663                 encode3to4( source, d+off, 3, outBuff, e, options );
664 
665                 lineLength += 4;
666                 if( breakLines && lineLength == MAX_LINE_LENGTH )
667                 {
668                     outBuff[e+4] = NEW_LINE;
669                     e++;
670                     lineLength = 0;
671                 }   // end if: end of line
672             }   // en dfor: each piece of array
673 
674             if( d < len )
675             {
676                 encode3to4( source, d+off, len - d, outBuff, e, options );
677                 e += 4;
678             }   // end if: some padding needed
679 
680 
681             // Return value according to relevant encoding.
682             try
683             {
684                 return new String( outBuff, 0, e, PREFERRED_ENCODING );
685             }   // end try
686             catch (java.io.UnsupportedEncodingException uue)
687             {
688                 return new String( outBuff, 0, e );
689             }   // end catch
690 
691         }   // end else: don't compress
692 
693     }   // end encodeBytes
694 
695 
696 
697 
698 
699 /* ********  D E C O D I N G   M E T H O D S  ******** */
700 
701 
702     /**
703      * Decodes four bytes from array <var>source</var>
704      * and writes the resulting bytes (up to three of them)
705      * to <var>destination</var>.
706      * The source and destination arrays can be manipulated
707      * anywhere along their length by specifying
708      * <var>srcOffset</var> and <var>destOffset</var>.
709      * This method does not check to make sure your arrays
710      * are large enough to accomodate <var>srcOffset</var> + 4 for
711      * the <var>source</var> array or <var>destOffset</var> + 3 for
712      * the <var>destination</var> array.
713      * This method returns the actual number of bytes that
714      * were converted from the Base64 encoding.
715 	 * <p>This is the lowest level of the decoding methods with
716 	 * all possible parameters.</p>
717      *
718      *
719      * @param source the array to convert
720      * @param srcOffset the index where conversion begins
721      * @param destination the array to hold the conversion
722      * @param destOffset the index where output will be put
723 	 * @param options alphabet type is pulled from this (standard, url-safe, ordered)
724      * @return the number of decoded bytes converted
725      * @since 1.3
726      */
decode4to3( byte[] source, int srcOffset, byte[] destination, int destOffset, int options )727     private static int decode4to3( byte[] source, int srcOffset, byte[] destination, int destOffset, int options )
728     {
729 		byte[] DECODABET = getDecodabet( options );
730 
731         // Example: Dk==
732         if( source[ srcOffset + 2] == EQUALS_SIGN )
733         {
734             // Two ways to do the same thing. Don't know which way I like best.
735             //int outBuff =   ( ( DECODABET[ source[ srcOffset    ] ] << 24 ) >>>  6 )
736             //              | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );
737             int outBuff =   ( ( DECODABET[ source[ srcOffset    ] ] & 0xFF ) << 18 )
738                           | ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 );
739 
740             destination[ destOffset ] = (byte)( outBuff >>> 16 );
741             return 1;
742         }
743 
744         // Example: DkL=
745         else if( source[ srcOffset + 3 ] == EQUALS_SIGN )
746         {
747             // Two ways to do the same thing. Don't know which way I like best.
748             //int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] << 24 ) >>>  6 )
749             //              | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
750             //              | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 );
751             int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] & 0xFF ) << 18 )
752                           | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
753                           | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) <<  6 );
754 
755             destination[ destOffset     ] = (byte)( outBuff >>> 16 );
756             destination[ destOffset + 1 ] = (byte)( outBuff >>>  8 );
757             return 2;
758         }
759 
760         // Example: DkLE
761         else
762         {
763             try{
764             // Two ways to do the same thing. Don't know which way I like best.
765             //int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] << 24 ) >>>  6 )
766             //              | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
767             //              | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 )
768             //              | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 );
769             int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] & 0xFF ) << 18 )
770                           | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
771                           | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) <<  6)
772                           | ( ( DECODABET[ source[ srcOffset + 3 ] ] & 0xFF )      );
773 
774 
775             destination[ destOffset     ] = (byte)( outBuff >> 16 );
776             destination[ destOffset + 1 ] = (byte)( outBuff >>  8 );
777             destination[ destOffset + 2 ] = (byte)( outBuff       );
778 
779             return 3;
780             }catch( Exception e){
781                 System.out.println(""+source[srcOffset]+ ": " + ( DECODABET[ source[ srcOffset     ] ]  ) );
782                 System.out.println(""+source[srcOffset+1]+  ": " + ( DECODABET[ source[ srcOffset + 1 ] ]  ) );
783                 System.out.println(""+source[srcOffset+2]+  ": " + ( DECODABET[ source[ srcOffset + 2 ] ]  ) );
784                 System.out.println(""+source[srcOffset+3]+  ": " + ( DECODABET[ source[ srcOffset + 3 ] ]  ) );
785                 return -1;
786             }   // end catch
787         }
788     }   // end decodeToBytes
789 
790 
791 
792 
793     /**
794      * Very low-level access to decoding ASCII characters in
795      * the form of a byte array. Does not support automatically
796      * gunzipping or any other "fancy" features.
797      *
798      * @param source The Base64 encoded data
799      * @param off    The offset of where to begin decoding
800      * @param len    The length of characters to decode
801      * @return decoded data
802      * @since 1.3
803      */
decode( byte[] source, int off, int len, int options )804     public static byte[] decode( byte[] source, int off, int len, int options )
805     {
806 		byte[] DECODABET = getDecodabet( options );
807 
808         int    len34   = len * 3 / 4;
809         byte[] outBuff = new byte[ len34 ]; // Upper limit on size of output
810         int    outBuffPosn = 0;
811 
812         byte[] b4        = new byte[4];
813         int    b4Posn    = 0;
814         int    i         = 0;
815         byte   sbiCrop   = 0;
816         byte   sbiDecode = 0;
817         for( i = off; i < off+len; i++ )
818         {
819             sbiCrop = (byte)(source[i] & 0x7f); // Only the low seven bits
820             sbiDecode = DECODABET[ sbiCrop ];
821 
822             if( sbiDecode >= WHITE_SPACE_ENC ) // White space, Equals sign or better
823             {
824                 if( sbiDecode >= EQUALS_SIGN_ENC )
825                 {
826                     b4[ b4Posn++ ] = sbiCrop;
827                     if( b4Posn > 3 )
828                     {
829                         outBuffPosn += decode4to3( b4, 0, outBuff, outBuffPosn, options );
830                         b4Posn = 0;
831 
832                         // If that was the equals sign, break out of 'for' loop
833                         if( sbiCrop == EQUALS_SIGN )
834                             break;
835                     }   // end if: quartet built
836 
837                 }   // end if: equals sign or better
838 
839             }   // end if: white space, equals sign or better
840             else
841             {
842                 System.err.println( "Bad Base64 input character at " + i + ": " + source[i] + "(decimal)" );
843                 return null;
844             }   // end else:
845         }   // each input character
846 
847         byte[] out = new byte[ outBuffPosn ];
848         System.arraycopy( outBuff, 0, out, 0, outBuffPosn );
849         return out;
850     }   // end decode
851 
852 
853 
854 
855     /**
856      * Decodes data from Base64 notation, automatically
857      * detecting gzip-compressed data and decompressing it.
858      *
859      * @param s the string to decode
860      * @return the decoded data
861      * @since 1.4
862      */
decode( String s )863     public static byte[] decode( String s )
864 	{
865 		return decode( s, NO_OPTIONS );
866 	}
867 
868 
869     /**
870      * Decodes data from Base64 notation, automatically
871      * detecting gzip-compressed data and decompressing it.
872      *
873      * @param s the string to decode
874 	 * @param options encode options such as URL_SAFE
875      * @return the decoded data
876      * @since 1.4
877      */
decode( String s, int options )878     public static byte[] decode( String s, int options )
879     {
880         byte[] bytes;
881         try
882         {
883             bytes = s.getBytes( PREFERRED_ENCODING );
884         }   // end try
885         catch( java.io.UnsupportedEncodingException uee )
886         {
887             bytes = s.getBytes();
888         }   // end catch
889 		//</change>
890 
891         // Decode
892         bytes = decode( bytes, 0, bytes.length, options );
893 
894 
895         // Check to see if it's gzip-compressed
896         // GZIP Magic Two-Byte Number: 0x8b1f (35615)
897         if( bytes != null && bytes.length >= 4 )
898         {
899 
900             int head = ((int)bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
901             if( java.util.zip.GZIPInputStream.GZIP_MAGIC == head )
902             {
903                 java.io.ByteArrayInputStream  bais = null;
904                 java.util.zip.GZIPInputStream gzis = null;
905                 java.io.ByteArrayOutputStream baos = null;
906                 byte[] buffer = new byte[2048];
907                 int    length = 0;
908 
909                 try
910                 {
911                     baos = new java.io.ByteArrayOutputStream();
912                     bais = new java.io.ByteArrayInputStream( bytes );
913                     gzis = new java.util.zip.GZIPInputStream( bais );
914 
915                     while( ( length = gzis.read( buffer ) ) >= 0 )
916                     {
917                         baos.write(buffer,0,length);
918                     }   // end while: reading input
919 
920                     // No error? Get new bytes.
921                     bytes = baos.toByteArray();
922 
923                 }   // end try
924                 catch( java.io.IOException e )
925                 {
926                     // Just return originally-decoded bytes
927                 }   // end catch
928                 finally
929                 {
930                     try{ baos.close(); } catch( Exception e ){}
931                     try{ gzis.close(); } catch( Exception e ){}
932                     try{ bais.close(); } catch( Exception e ){}
933                 }   // end finally
934 
935             }   // end if: gzipped
936         }   // end if: bytes.length >= 2
937 
938         return bytes;
939     }   // end decode
940 
941 
942 
943 
944     /**
945      * Attempts to decode Base64 data and deserialize a Java
946      * Object within. Returns <tt>null</tt> if there was an error.
947      *
948      * @param encodedObject The Base64 data to decode
949      * @return The decoded and deserialized object
950      * @since 1.5
951      */
decodeToObject( String encodedObject )952     public static Object decodeToObject( String encodedObject )
953     {
954         // Decode and gunzip if necessary
955         byte[] objBytes = decode( encodedObject );
956 
957         java.io.ByteArrayInputStream  bais = null;
958         java.io.ObjectInputStream     ois  = null;
959         Object obj = null;
960 
961         try
962         {
963             bais = new java.io.ByteArrayInputStream( objBytes );
964             ois  = new java.io.ObjectInputStream( bais );
965 
966             obj = ois.readObject();
967         }   // end try
968         catch( java.io.IOException e )
969         {
970             e.printStackTrace();
971             obj = null;
972         }   // end catch
973         catch( java.lang.ClassNotFoundException e )
974         {
975             e.printStackTrace();
976             obj = null;
977         }   // end catch
978         finally
979         {
980             try{ bais.close(); } catch( Exception e ){}
981             try{ ois.close();  } catch( Exception e ){}
982         }   // end finally
983 
984         return obj;
985     }   // end decodeObject
986 
987 
988 
989     /**
990      * Convenience method for encoding data to a file.
991      *
992      * @param dataToEncode byte array of data to encode in base64 form
993      * @param filename Filename for saving encoded data
994      * @return <tt>true</tt> if successful, <tt>false</tt> otherwise
995      *
996      * @since 2.1
997      */
encodeToFile( byte[] dataToEncode, String filename )998     public static boolean encodeToFile( byte[] dataToEncode, String filename )
999     {
1000         boolean success = false;
1001         Base64.OutputStream bos = null;
1002         try
1003         {
1004             bos = new Base64.OutputStream(
1005                       new java.io.FileOutputStream( filename ), Base64.ENCODE );
1006             bos.write( dataToEncode );
1007             success = true;
1008         }   // end try
1009         catch( java.io.IOException e )
1010         {
1011 
1012             success = false;
1013         }   // end catch: IOException
1014         finally
1015         {
1016             try{ bos.close(); } catch( Exception e ){}
1017         }   // end finally
1018 
1019         return success;
1020     }   // end encodeToFile
1021 
1022 
1023     /**
1024      * Convenience method for decoding data to a file.
1025      *
1026      * @param dataToDecode Base64-encoded data as a string
1027      * @param filename Filename for saving decoded data
1028      * @return <tt>true</tt> if successful, <tt>false</tt> otherwise
1029      *
1030      * @since 2.1
1031      */
decodeToFile( String dataToDecode, String filename )1032     public static boolean decodeToFile( String dataToDecode, String filename )
1033     {
1034         boolean success = false;
1035         Base64.OutputStream bos = null;
1036         try
1037         {
1038                 bos = new Base64.OutputStream(
1039                           new java.io.FileOutputStream( filename ), Base64.DECODE );
1040                 bos.write( dataToDecode.getBytes( PREFERRED_ENCODING ) );
1041                 success = true;
1042         }   // end try
1043         catch( java.io.IOException e )
1044         {
1045             success = false;
1046         }   // end catch: IOException
1047         finally
1048         {
1049                 try{ bos.close(); } catch( Exception e ){}
1050         }   // end finally
1051 
1052         return success;
1053     }   // end decodeToFile
1054 
1055 
1056 
1057 
1058     /**
1059      * Convenience method for reading a base64-encoded
1060      * file and decoding it.
1061      *
1062      * @param filename Filename for reading encoded data
1063      * @return decoded byte array or null if unsuccessful
1064      *
1065      * @since 2.1
1066      */
decodeFromFile( String filename )1067     public static byte[] decodeFromFile( String filename )
1068     {
1069         byte[] decodedData = null;
1070         Base64.InputStream bis = null;
1071         try
1072         {
1073             // Set up some useful variables
1074             java.io.File file = new java.io.File( filename );
1075             byte[] buffer = null;
1076             int length   = 0;
1077             int numBytes = 0;
1078 
1079             // Check for size of file
1080             if( file.length() > Integer.MAX_VALUE )
1081             {
1082                 System.err.println( "File is too big for this convenience method (" + file.length() + " bytes)." );
1083                 return null;
1084             }   // end if: file too big for int index
1085             buffer = new byte[ (int)file.length() ];
1086 
1087             // Open a stream
1088             bis = new Base64.InputStream(
1089                       new java.io.BufferedInputStream(
1090                       new java.io.FileInputStream( file ) ), Base64.DECODE );
1091 
1092             // Read until done
1093             while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 )
1094                 length += numBytes;
1095 
1096             // Save in a variable to return
1097             decodedData = new byte[ length ];
1098             System.arraycopy( buffer, 0, decodedData, 0, length );
1099 
1100         }   // end try
1101         catch( java.io.IOException e )
1102         {
1103             System.err.println( "Error decoding from file " + filename );
1104         }   // end catch: IOException
1105         finally
1106         {
1107             try{ bis.close(); } catch( Exception e) {}
1108         }   // end finally
1109 
1110         return decodedData;
1111     }   // end decodeFromFile
1112 
1113 
1114 
1115     /**
1116      * Convenience method for reading a binary file
1117      * and base64-encoding it.
1118      *
1119      * @param filename Filename for reading binary data
1120      * @return base64-encoded string or null if unsuccessful
1121      *
1122      * @since 2.1
1123      */
encodeFromFile( String filename )1124     public static String encodeFromFile( String filename )
1125     {
1126         String encodedData = null;
1127         Base64.InputStream bis = null;
1128         try
1129         {
1130             // Set up some useful variables
1131             java.io.File file = new java.io.File( filename );
1132             byte[] buffer = new byte[ Math.max((int)(file.length() * 1.4),40) ]; // Need max() for math on small files (v2.2.1)
1133             int length   = 0;
1134             int numBytes = 0;
1135 
1136             // Open a stream
1137             bis = new Base64.InputStream(
1138                       new java.io.BufferedInputStream(
1139                       new java.io.FileInputStream( file ) ), Base64.ENCODE );
1140 
1141             // Read until done
1142             while( ( numBytes = bis.read( buffer, length, 4096 ) ) >= 0 )
1143                 length += numBytes;
1144 
1145             // Save in a variable to return
1146             encodedData = new String( buffer, 0, length, Base64.PREFERRED_ENCODING );
1147 
1148         }   // end try
1149         catch( java.io.IOException e )
1150         {
1151             System.err.println( "Error encoding from file " + filename );
1152         }   // end catch: IOException
1153         finally
1154         {
1155             try{ bis.close(); } catch( Exception e) {}
1156         }   // end finally
1157 
1158         return encodedData;
1159         }   // end encodeFromFile
1160 
1161     /**
1162      * Reads <tt>infile</tt> and encodes it to <tt>outfile</tt>.
1163      *
1164      * @param infile Input file
1165      * @param outfile Output file
1166      * @since 2.2
1167      */
encodeFileToFile( String infile, String outfile )1168     public static void encodeFileToFile( String infile, String outfile )
1169     {
1170         String encoded = Base64.encodeFromFile( infile );
1171         java.io.OutputStream out = null;
1172         try{
1173             out = new java.io.BufferedOutputStream(
1174                   new java.io.FileOutputStream( outfile ) );
1175             out.write( encoded.getBytes("US-ASCII") ); // Strict, 7-bit output.
1176         }   // end try
1177         catch( java.io.IOException ex ) {
1178             ex.printStackTrace();
1179         }   // end catch
1180         finally {
1181             try { out.close(); }
1182             catch( Exception ex ){}
1183         }   // end finally
1184     }   // end encodeFileToFile
1185 
1186 
1187     /**
1188      * Reads <tt>infile</tt> and decodes it to <tt>outfile</tt>.
1189      *
1190      * @param infile Input file
1191      * @param outfile Output file
1192      * @since 2.2
1193      */
decodeFileToFile( String infile, String outfile )1194     public static void decodeFileToFile( String infile, String outfile )
1195     {
1196         byte[] decoded = Base64.decodeFromFile( infile );
1197         java.io.OutputStream out = null;
1198         try{
1199             out = new java.io.BufferedOutputStream(
1200                   new java.io.FileOutputStream( outfile ) );
1201             out.write( decoded );
1202         }   // end try
1203         catch( java.io.IOException ex ) {
1204             ex.printStackTrace();
1205         }   // end catch
1206         finally {
1207             try { out.close(); }
1208             catch( Exception ex ){}
1209         }   // end finally
1210     }   // end decodeFileToFile
1211 
1212 
1213     /* ********  I N N E R   C L A S S   I N P U T S T R E A M  ******** */
1214 
1215 
1216 
1217     /**
1218      * A {@link Base64.InputStream} will read data from another
1219      * <tt>java.io.InputStream</tt>, given in the constructor,
1220      * and encode/decode to/from Base64 notation on the fly.
1221      *
1222      * @see Base64
1223      * @since 1.3
1224      */
1225     public static class InputStream extends java.io.FilterInputStream
1226     {
1227         private boolean encode;         // Encoding or decoding
1228         private int     position;       // Current position in the buffer
1229         private byte[]  buffer;         // Small buffer holding converted data
1230         private int     bufferLength;   // Length of buffer (3 or 4)
1231         private int     numSigBytes;    // Number of meaningful bytes in the buffer
1232         private int     lineLength;
1233         private boolean breakLines;     // Break lines at less than 80 characters
1234 		private int     options;        // Record options used to create the stream.
1235 		private byte[]  alphabet;	    // Local copies to avoid extra method calls
1236 		private byte[]  decodabet;		// Local copies to avoid extra method calls
1237 
1238 
1239         /**
1240          * Constructs a {@link Base64.InputStream} in DECODE mode.
1241          *
1242          * @param in the <tt>java.io.InputStream</tt> from which to read data.
1243          * @since 1.3
1244          */
InputStream( java.io.InputStream in )1245         public InputStream( java.io.InputStream in )
1246         {
1247             this( in, DECODE );
1248         }   // end constructor
1249 
1250 
1251         /**
1252          * Constructs a {@link Base64.InputStream} in
1253          * either ENCODE or DECODE mode.
1254          * <p>
1255          * Valid options:<pre>
1256          *   ENCODE or DECODE: Encode or Decode as data is read.
1257          *   DONT_BREAK_LINES: don't break lines at 76 characters
1258          *     (only meaningful when encoding)
1259          *     <i>Note: Technically, this makes your encoding non-compliant.</i>
1260          * </pre>
1261          * <p>
1262          * Example: <code>new Base64.InputStream( in, Base64.DECODE )</code>
1263          *
1264          *
1265          * @param in the <tt>java.io.InputStream</tt> from which to read data.
1266          * @param options Specified options
1267          * @see Base64#ENCODE
1268          * @see Base64#DECODE
1269          * @see Base64#DONT_BREAK_LINES
1270          * @since 2.0
1271          */
InputStream( java.io.InputStream in, int options )1272         public InputStream( java.io.InputStream in, int options )
1273         {
1274             super( in );
1275             this.breakLines   = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
1276             this.encode       = (options & ENCODE) == ENCODE;
1277             this.bufferLength = encode ? 4 : 3;
1278             this.buffer       = new byte[ bufferLength ];
1279             this.position     = -1;
1280             this.lineLength   = 0;
1281 			this.options      = options; // Record for later, mostly to determine which alphabet to use
1282 			this.alphabet     = getAlphabet(options);
1283 			this.decodabet    = getDecodabet(options);
1284         }   // end constructor
1285 
1286         /**
1287          * Reads enough of the input stream to convert
1288          * to/from Base64 and returns the next byte.
1289          *
1290          * @return next byte
1291          * @since 1.3
1292          */
read()1293         public int read() throws java.io.IOException
1294         {
1295             // Do we need to get data?
1296             if( position < 0 )
1297             {
1298                 if( encode )
1299                 {
1300                     byte[] b3 = new byte[3];
1301                     int numBinaryBytes = 0;
1302                     for( int i = 0; i < 3; i++ )
1303                     {
1304                         try
1305                         {
1306                             int b = in.read();
1307 
1308                             // If end of stream, b is -1.
1309                             if( b >= 0 )
1310                             {
1311                                 b3[i] = (byte)b;
1312                                 numBinaryBytes++;
1313                             }   // end if: not end of stream
1314 
1315                         }   // end try: read
1316                         catch( java.io.IOException e )
1317                         {
1318                             // Only a problem if we got no data at all.
1319                             if( i == 0 )
1320                                 throw e;
1321 
1322                         }   // end catch
1323                     }   // end for: each needed input byte
1324 
1325                     if( numBinaryBytes > 0 )
1326                     {
1327                         encode3to4( b3, 0, numBinaryBytes, buffer, 0, options );
1328                         position = 0;
1329                         numSigBytes = 4;
1330                     }   // end if: got data
1331                     else
1332                     {
1333                         return -1;
1334                     }   // end else
1335                 }   // end if: encoding
1336 
1337                 // Else decoding
1338                 else
1339                 {
1340                     byte[] b4 = new byte[4];
1341                     int i = 0;
1342                     for( i = 0; i < 4; i++ )
1343                     {
1344                         // Read four "meaningful" bytes:
1345                         int b = 0;
1346                         do{ b = in.read(); }
1347                         while( b >= 0 && decodabet[ b & 0x7f ] <= WHITE_SPACE_ENC );
1348 
1349                         if( b < 0 )
1350                             break; // Reads a -1 if end of stream
1351 
1352                         b4[i] = (byte)b;
1353                     }   // end for: each needed input byte
1354 
1355                     if( i == 4 )
1356                     {
1357                         numSigBytes = decode4to3( b4, 0, buffer, 0, options );
1358                         position = 0;
1359                     }   // end if: got four characters
1360                     else if( i == 0 ){
1361                         return -1;
1362                     }   // end else if: also padded correctly
1363                     else
1364                     {
1365                         // Must have broken out from above.
1366                         throw new java.io.IOException( "Improperly padded Base64 input." );
1367                     }   // end
1368 
1369                 }   // end else: decode
1370             }   // end else: get data
1371 
1372             // Got data?
1373             if( position >= 0 )
1374             {
1375                 // End of relevant data?
1376                 if( /*!encode &&*/ position >= numSigBytes )
1377                     return -1;
1378 
1379                 if( encode && breakLines && lineLength >= MAX_LINE_LENGTH )
1380                 {
1381                     lineLength = 0;
1382                     return '\n';
1383                 }   // end if
1384                 else
1385                 {
1386                     lineLength++;   // This isn't important when decoding
1387                                     // but throwing an extra "if" seems
1388                                     // just as wasteful.
1389 
1390                     int b = buffer[ position++ ];
1391 
1392                     if( position >= bufferLength )
1393                         position = -1;
1394 
1395                     return b & 0xFF; // This is how you "cast" a byte that's
1396                                      // intended to be unsigned.
1397                 }   // end else
1398             }   // end if: position >= 0
1399 
1400             // Else error
1401             else
1402             {
1403                 // When JDK1.4 is more accepted, use an assertion here.
1404                 throw new java.io.IOException( "Error in Base64 code reading stream." );
1405             }   // end else
1406         }   // end read
1407 
1408 
1409         /**
1410          * Calls {@link #read()} repeatedly until the end of stream
1411          * is reached or <var>len</var> bytes are read.
1412          * Returns number of bytes read into array or -1 if
1413          * end of stream is encountered.
1414          *
1415          * @param dest array to hold values
1416          * @param off offset for array
1417          * @param len max number of bytes to read into array
1418          * @return bytes read into array or -1 if end of stream is encountered.
1419          * @since 1.3
1420          */
read( byte[] dest, int off, int len )1421         public int read( byte[] dest, int off, int len ) throws java.io.IOException
1422         {
1423             int i;
1424             int b;
1425             for( i = 0; i < len; i++ )
1426             {
1427                 b = read();
1428 
1429                 //if( b < 0 && i == 0 )
1430                 //    return -1;
1431 
1432                 if( b >= 0 )
1433                     dest[off + i] = (byte)b;
1434                 else if( i == 0 )
1435                     return -1;
1436                 else
1437                     break; // Out of 'for' loop
1438             }   // end for: each byte read
1439             return i;
1440         }   // end read
1441 
1442     }   // end inner class InputStream
1443 
1444 
1445 
1446 
1447 
1448 
1449     /* ********  I N N E R   C L A S S   O U T P U T S T R E A M  ******** */
1450 
1451 
1452 
1453     /**
1454      * A {@link Base64.OutputStream} will write data to another
1455      * <tt>java.io.OutputStream</tt>, given in the constructor,
1456      * and encode/decode to/from Base64 notation on the fly.
1457      *
1458      * @see Base64
1459      * @since 1.3
1460      */
1461     public static class OutputStream extends java.io.FilterOutputStream
1462     {
1463         private boolean encode;
1464         private int     position;
1465         private byte[]  buffer;
1466         private int     bufferLength;
1467         private int     lineLength;
1468         private boolean breakLines;
1469         private byte[]  b4; // Scratch used in a few places
1470         private boolean suspendEncoding;
1471 		private int options; // Record for later
1472 		private byte[]  alphabet;	    // Local copies to avoid extra method calls
1473 		private byte[]  decodabet;		// Local copies to avoid extra method calls
1474 
1475         /**
1476          * Constructs a {@link Base64.OutputStream} in ENCODE mode.
1477          *
1478          * @param out the <tt>java.io.OutputStream</tt> to which data will be written.
1479          * @since 1.3
1480          */
OutputStream( java.io.OutputStream out )1481         public OutputStream( java.io.OutputStream out )
1482         {
1483             this( out, ENCODE );
1484         }   // end constructor
1485 
1486 
1487         /**
1488          * Constructs a {@link Base64.OutputStream} in
1489          * either ENCODE or DECODE mode.
1490          * <p>
1491          * Valid options:<pre>
1492          *   ENCODE or DECODE: Encode or Decode as data is read.
1493          *   DONT_BREAK_LINES: don't break lines at 76 characters
1494          *     (only meaningful when encoding)
1495          *     <i>Note: Technically, this makes your encoding non-compliant.</i>
1496          * </pre>
1497          * <p>
1498          * Example: <code>new Base64.OutputStream( out, Base64.ENCODE )</code>
1499          *
1500          * @param out the <tt>java.io.OutputStream</tt> to which data will be written.
1501          * @param options Specified options.
1502          * @see Base64#ENCODE
1503          * @see Base64#DECODE
1504          * @see Base64#DONT_BREAK_LINES
1505          * @since 1.3
1506          */
OutputStream( java.io.OutputStream out, int options )1507         public OutputStream( java.io.OutputStream out, int options )
1508         {
1509             super( out );
1510             this.breakLines   = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
1511             this.encode       = (options & ENCODE) == ENCODE;
1512             this.bufferLength = encode ? 3 : 4;
1513             this.buffer       = new byte[ bufferLength ];
1514             this.position     = 0;
1515             this.lineLength   = 0;
1516             this.suspendEncoding = false;
1517             this.b4           = new byte[4];
1518 			this.options      = options;
1519 			this.alphabet     = getAlphabet(options);
1520 			this.decodabet    = getDecodabet(options);
1521         }   // end constructor
1522 
1523 
1524         /**
1525          * Writes the byte to the output stream after
1526          * converting to/from Base64 notation.
1527          * When encoding, bytes are buffered three
1528          * at a time before the output stream actually
1529          * gets a write() call.
1530          * When decoding, bytes are buffered four
1531          * at a time.
1532          *
1533          * @param theByte the byte to write
1534          * @since 1.3
1535          */
write(int theByte)1536         public void write(int theByte) throws java.io.IOException
1537         {
1538             // Encoding suspended?
1539             if( suspendEncoding )
1540             {
1541                 super.out.write( theByte );
1542                 return;
1543             }   // end if: supsended
1544 
1545             // Encode?
1546             if( encode )
1547             {
1548                 buffer[ position++ ] = (byte)theByte;
1549                 if( position >= bufferLength )  // Enough to encode.
1550                 {
1551                     out.write( encode3to4( b4, buffer, bufferLength, options ) );
1552 
1553                     lineLength += 4;
1554                     if( breakLines && lineLength >= MAX_LINE_LENGTH )
1555                     {
1556                         out.write( NEW_LINE );
1557                         lineLength = 0;
1558                     }   // end if: end of line
1559 
1560                     position = 0;
1561                 }   // end if: enough to output
1562             }   // end if: encoding
1563 
1564             // Else, Decoding
1565             else
1566             {
1567                 // Meaningful Base64 character?
1568                 if( decodabet[ theByte & 0x7f ] > WHITE_SPACE_ENC )
1569                 {
1570                     buffer[ position++ ] = (byte)theByte;
1571                     if( position >= bufferLength )  // Enough to output.
1572                     {
1573                         int len = Base64.decode4to3( buffer, 0, b4, 0, options );
1574                         out.write( b4, 0, len );
1575                         //out.write( Base64.decode4to3( buffer ) );
1576                         position = 0;
1577                     }   // end if: enough to output
1578                 }   // end if: meaningful base64 character
1579                 else if( decodabet[ theByte & 0x7f ] != WHITE_SPACE_ENC )
1580                 {
1581                     throw new java.io.IOException( "Invalid character in Base64 data." );
1582                 }   // end else: not white space either
1583             }   // end else: decoding
1584         }   // end write
1585 
1586 
1587 
1588         /**
1589          * Calls {@link #write(int)} repeatedly until <var>len</var>
1590          * bytes are written.
1591          *
1592          * @param theBytes array from which to read bytes
1593          * @param off offset for array
1594          * @param len max number of bytes to read into array
1595          * @since 1.3
1596          */
write( byte[] theBytes, int off, int len )1597         public void write( byte[] theBytes, int off, int len ) throws java.io.IOException
1598         {
1599             // Encoding suspended?
1600             if( suspendEncoding )
1601             {
1602                 super.out.write( theBytes, off, len );
1603                 return;
1604             }   // end if: supsended
1605 
1606             for( int i = 0; i < len; i++ )
1607             {
1608                 write( theBytes[ off + i ] );
1609             }   // end for: each byte written
1610 
1611         }   // end write
1612 
1613 
1614 
1615         /**
1616          * Method added by PHIL. [Thanks, PHIL. -Rob]
1617          * This pads the buffer without closing the stream.
1618          */
flushBase64()1619         public void flushBase64() throws java.io.IOException
1620         {
1621             if( position > 0 )
1622             {
1623                 if( encode )
1624                 {
1625                     out.write( encode3to4( b4, buffer, position, options ) );
1626                     position = 0;
1627                 }   // end if: encoding
1628                 else
1629                 {
1630                     throw new java.io.IOException( "Base64 input not properly padded." );
1631                 }   // end else: decoding
1632             }   // end if: buffer partially full
1633 
1634         }   // end flush
1635 
1636 
1637         /**
1638          * Flushes and closes (I think, in the superclass) the stream.
1639          *
1640          * @since 1.3
1641          */
close()1642         public void close() throws java.io.IOException
1643         {
1644             // 1. Ensure that pending characters are written
1645             flushBase64();
1646 
1647             // 2. Actually close the stream
1648             // Base class both flushes and closes.
1649             super.close();
1650 
1651             buffer = null;
1652             out    = null;
1653         }   // end close
1654 
1655 
1656 
1657         /**
1658          * Suspends encoding of the stream.
1659          * May be helpful if you need to embed a piece of
1660          * base640-encoded data in a stream.
1661          *
1662          * @since 1.5.1
1663          */
suspendEncoding()1664         public void suspendEncoding() throws java.io.IOException
1665         {
1666             flushBase64();
1667             this.suspendEncoding = true;
1668         }   // end suspendEncoding
1669 
1670 
1671         /**
1672          * Resumes encoding of the stream.
1673          * May be helpful if you need to embed a piece of
1674          * base640-encoded data in a stream.
1675          *
1676          * @since 1.5.1
1677          */
resumeEncoding()1678         public void resumeEncoding()
1679         {
1680             this.suspendEncoding = false;
1681         }   // end resumeEncoding
1682 
1683 
1684 
1685     }   // end inner class OutputStream
1686 
1687 
1688 }   // end class Base64
1689 
1690