source: release-kits/wirk3/ant-scripts/tasks/antelope/src/ise/antelope/tasks/util/Base64.java@ 15023

Last change on this file since 15023 was 15023, checked in by oranfry, 16 years ago

did the bulk of the work on wirk3

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