EMMA Coverage Report (generated Wed Oct 26 13:47:17 EDT 2011)
[all classes][org.jclouds.encryption.internal]

COVERAGE SUMMARY FOR SOURCE FILE [Base64.java]

nameclass, %method, %block, %line, %
Base64.java67%  (2/3)38%  (13/34)58%  (1545/2653)38%  (134.9/358)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class Base64$OutputStream0%   (0/1)0%   (0/8)0%   (0/245)0%   (0/56)
Base64$OutputStream (OutputStream): void 0%   (0/1)0%   (0/5)0%   (0/2)
Base64$OutputStream (OutputStream, int): void 0%   (0/1)0%   (0/50)0%   (0/10)
close (): void 0%   (0/1)0%   (0/11)0%   (0/5)
flushBase64 (): void 0%   (0/1)0%   (0/26)0%   (0/6)
resumeEncoding (): void 0%   (0/1)0%   (0/4)0%   (0/2)
suspendEncoding (): void 0%   (0/1)0%   (0/6)0%   (0/3)
write (byte [], int, int): void 0%   (0/1)0%   (0/25)0%   (0/6)
write (int): void 0%   (0/1)0%   (0/118)0%   (0/22)
     
class Base64100% (1/1)45%  (10/22)62%  (1331/2160)35%  (84.3/239)
Base64 (): void 0%   (0/1)0%   (0/3)0%   (0/1)
access$300 (byte [], byte [], int): byte [] 0%   (0/1)0%   (0/5)0%   (0/1)
decodeFromFile (String): byte [] 0%   (0/1)0%   (0/110)0%   (0/20)
decodeToFile (String, String): boolean 0%   (0/1)0%   (0/42)0%   (0/10)
decodeToObject (String): Object 0%   (0/1)0%   (0/72)0%   (0/17)
encode3to4 (byte [], byte [], int): byte [] 0%   (0/1)0%   (0/9)0%   (0/2)
encodeBytes (byte []): String 0%   (0/1)0%   (0/7)0%   (0/1)
encodeBytes (byte [], int, int): String 0%   (0/1)0%   (0/6)0%   (0/1)
encodeFromFile (String): String 0%   (0/1)0%   (0/84)0%   (0/15)
encodeObject (Serializable): String 0%   (0/1)0%   (0/4)0%   (0/1)
encodeObject (Serializable, int): String 0%   (0/1)0%   (0/123)0%   (0/24)
encodeToFile (byte [], String): boolean 0%   (0/1)0%   (0/40)0%   (0/10)
decode (String): byte [] 100% (1/1)30%  (36/122)28%  (7/25)
encodeBytes (byte [], int, int, int): String 100% (1/1)43%  (87/204)43%  (17.6/41)
decode4to3 (byte [], int, byte [], int): int 100% (1/1)64%  (166/261)70%  (14/20)
decode (byte [], int, int): byte [] 100% (1/1)80%  (81/101)92%  (22/24)
encode3to4 (byte [], int, int, byte [], int): byte [] 100% (1/1)98%  (161/164)94%  (17/18)
<static initializer> 100% (1/1)100% (778/781)71%  (5/7)
access$000 (byte [], int, int, byte [], int): byte [] 100% (1/1)100% (7/7)100% (1/1)
access$100 (): byte [] 100% (1/1)100% (2/2)100% (1/1)
access$200 (byte [], int, byte [], int): int 100% (1/1)100% (6/6)100% (1/1)
encodeBytes (byte [], int): String 100% (1/1)100% (7/7)100% (1/1)
     
class Base64$InputStream100% (1/1)75%  (3/4)86%  (214/248)80%  (50.6/63)
Base64$InputStream (InputStream): void 0%   (0/1)0%   (0/5)0%   (0/2)
read (): int 100% (1/1)83%  (145/174)77%  (35.6/46)
Base64$InputStream (InputStream, int): void 100% (1/1)100% (43/43)100% (8/8)
read (byte [], int, int): int 100% (1/1)100% (26/26)100% (7/7)

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

[all classes][org.jclouds.encryption.internal]
EMMA 2.0.5312 (C) Vladimir Roubtsov