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