PageRenderTime 87ms CodeModel.GetById 11ms app.highlight 64ms RepoModel.GetById 1ms app.codeStats 0ms

/razpub/src/com/razie/pub/util/Base64.java

http://razpub.googlecode.com/
Java | 1484 lines | 598 code | 207 blank | 679 comment | 81 complexity | 0780a32f96951b7765d039b8146f5d90 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1package com.razie.pub.util;
   2/**
   3 * <p>Encodes and decodes to and from Base64 notation.</p>
   4 * <p>Homepage: <a href="http://iharder.net/base64">http://iharder.net/base64</a>.</p>
   5 * 
   6 * <p>Example:</p>
   7 * 
   8 * <code>String encoded = Base64.encode( myByteArray );</code>
   9 * <br />
  10 * <code>byte[] myByteArray = Base64.decode( encoded );</code>
  11 *
  12 * <p>The <tt>options</tt> parameter, which appears in a few places, is used to pass 
  13 * several pieces of information to the encoder. In the "higher level" methods such as 
  14 * encodeBytes( bytes, options ) the options parameter can be used to indicate such 
  15 * things as first gzipping the bytes before encoding them, not inserting linefeeds,
  16 * and encoding using the URL-safe and Ordered dialects.</p>
  17 *
  18 * <p>Note, according to <a href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>,
  19 * Section 2.1, implementations should not add line feeds unless explicitly told
  20 * to do so. I've got Base64 set to this behavior now, although earlier versions
  21 * broke lines by default.</p>
  22 *
  23 * <p>The constants defined in Base64 can be OR-ed together to combine options, so you 
  24 * might make a call like this:</p>
  25 *
  26 * <code>String encoded = Base64.encodeBytes( mybytes, Base64.GZIP | Base64.DO_BREAK_LINES );</code>
  27 * <p>to compress the data before encoding it and then making the output have newline characters.</p>
  28 * <p>Also...</p>
  29 * <code>String encoded = Base64.encodeBytes( crazyString.getBytes() );</code>
  30 *
  31 *
  32 *
  33 * <p>
  34 * Change Log:
  35 * </p>
  36 * <ul>
  37 *  <li>v2.3.4 - Fixed bug when working with gzipped streams whereby flushing
  38 *   the Base64.OutputStream closed the Base64 encoding (by padding with equals
  39 *   signs) too soon. Also added an option to suppress the automatic decoding
  40 *   of gzipped streams. Also added experimental support for specifying a
  41 *   class loader when using the
  42 *   {@link #decodeToObject(java.lang.String, int, java.lang.ClassLoader)}
  43 *   method.</li>
  44 *  <li>v2.3.3 - Changed default char encoding to US-ASCII which reduces the internal Java
  45 *   footprint with its CharEncoders and so forth. Fixed some javadocs that were
  46 *   inconsistent. Removed imports and specified things like java.io.IOException
  47 *   explicitly inline.</li>
  48 *  <li>v2.3.2 - Reduced memory footprint! Finally refined the "guessing" of how big the
  49 *   final encoded data will be so that the code doesn't have to create two output
  50 *   arrays: an oversized initial one and then a final, exact-sized one. Big win
  51 *   when using the {@link #encodeBytesToBytes(byte[])} family of methods (and not
  52 *   using the gzip options which uses a different mechanism with streams and stuff).</li>
  53 *  <li>v2.3.1 - Added {@link #encodeBytesToBytes(byte[], int, int, int)} and some
  54 *   similar helper methods to be more efficient with memory by not returning a
  55 *   String but just a byte array.</li>
  56 *  <li>v2.3 - <strong>This is not a drop-in replacement!</strong> This is two years of comments
  57 *   and bug fixes queued up and finally executed. Thanks to everyone who sent
  58 *   me stuff, and I'm sorry I wasn't able to distribute your fixes to everyone else.
  59 *   Much bad coding was cleaned up including throwing exceptions where necessary 
  60 *   instead of returning null values or something similar. Here are some changes
  61 *   that may affect you:
  62 *   <ul>
  63 *    <li><em>Does not break lines, by default.</em> This is to keep in compliance with
  64 *      <a href="http://www.faqs.org/rfcs/rfc3548.html">RFC3548</a>.</li>
  65 *    <li><em>Throws exceptions instead of returning null values.</em> Because some operations
  66 *      (especially those that may permit the GZIP option) use IO streams, there
  67 *      is a possiblity of an java.io.IOException being thrown. After some discussion and
  68 *      thought, I've changed the behavior of the methods to throw java.io.IOExceptions
  69 *      rather than return null if ever there's an error. I think this is more
  70 *      appropriate, though it will require some changes to your code. Sorry,
  71 *      it should have been done this way to begin with.</li>
  72 *    <li><em>Removed all references to System.out, System.err, and the like.</em>
  73 *      Shame on me. All I can say is sorry they were ever there.</li>
  74 *    <li><em>Throws NullPointerExceptions and IllegalArgumentExceptions</em> as needed
  75 *      such as when passed arrays are null or offsets are invalid.</li>
  76 *    <li>Cleaned up as much javadoc as I could to avoid any javadoc warnings.
  77 *      This was especially annoying before for people who were thorough in their
  78 *      own projects and then had gobs of javadoc warnings on this file.</li>
  79 *   </ul>
  80 *  <li>v2.2.1 - Fixed bug using URL_SAFE and ORDERED encodings. Fixed bug
  81 *   when using very small files (~< 40 bytes).</li>
  82 *  <li>v2.2 - Added some helper methods for encoding/decoding directly from
  83 *   one file to the next. Also added a main() method to support command line
  84 *   encoding/decoding from one file to the next. Also added these Base64 dialects:
  85 *   <ol>
  86 *   <li>The default is RFC3548 format.</li>
  87 *   <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.URLSAFE_FORMAT) generates
  88 *   URL and file name friendly format as described in Section 4 of RFC3548.
  89 *   http://www.faqs.org/rfcs/rfc3548.html</li>
  90 *   <li>Calling Base64.setFormat(Base64.BASE64_FORMAT.ORDERED_FORMAT) generates
  91 *   URL and file name friendly format that preserves lexical ordering as described
  92 *   in http://www.faqs.org/qa/rfcc-1940.html</li>
  93 *   </ol>
  94 *   Special thanks to Jim Kellerman at <a href="http://www.powerset.com/">http://www.powerset.com/</a>
  95 *   for contributing the new Base64 dialects.
  96 *  </li>
  97 * 
  98 *  <li>v2.1 - Cleaned up javadoc comments and unused variables and methods. Added
  99 *   some convenience methods for reading and writing to and from files.</li>
 100 *  <li>v2.0.2 - Now specifies UTF-8 encoding in places where the code fails on systems
 101 *   with other encodings (like EBCDIC).</li>
 102 *  <li>v2.0.1 - Fixed an error when decoding a single byte, that is, when the
 103 *   encoded data was a single byte.</li>
 104 *  <li>v2.0 - I got rid of methods that used booleans to set options. 
 105 *   Now everything is more consolidated and cleaner. The code now detects
 106 *   when data that's being decoded is gzip-compressed and will decompress it
 107 *   automatically. Generally things are cleaner. You'll probably have to
 108 *   change some method calls that you were making to support the new
 109 *   options format (<tt>int</tt>s that you "OR" together).</li>
 110 *  <li>v1.5.1 - Fixed bug when decompressing and decoding to a             
 111 *   byte[] using <tt>decode( String s, boolean gzipCompressed )</tt>.      
 112 *   Added the ability to "suspend" encoding in the Output Stream so        
 113 *   you can turn on and off the encoding if you need to embed base64       
 114 *   data in an otherwise "normal" stream (like an XML file).</li>  
 115 *  <li>v1.5 - Output stream pases on flush() command but doesn't do anything itself.
 116 *      This helps when using GZIP streams.
 117 *      Added the ability to GZip-compress objects before encoding them.</li>
 118 *  <li>v1.4 - Added helper methods to read/write files.</li>
 119 *  <li>v1.3.6 - Fixed OutputStream.flush() so that 'position' is reset.</li>
 120 *  <li>v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream
 121 *      where last buffer being read, if not completely full, was not returned.</li>
 122 *  <li>v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.</li>
 123 *  <li>v1.3.3 - Fixed I/O streams which were totally messed up.</li>
 124 * </ul>
 125 *
 126 * <p>
 127 * I am placing this code in the Public Domain. Do with it as you will.
 128 * This software comes with no guarantees or warranties but with
 129 * plenty of well-wishing instead!
 130 * Please visit <a href="http://iharder.net/base64">http://iharder.net/base64</a>
 131 * periodically to check for updates or to contribute improvements.
 132 * </p>
 133 *
 134 * @author Robert Harder
 135 * @author rob@iharder.net
 136 * @version 2.3.3
 137 */
 138public class Base64
 139{
 140    
 141/* ********  P U B L I C   F I E L D S  ******** */   
 142    
 143    
 144    /** No options specified. Value is zero. */
 145    public final static int NO_OPTIONS = 0;
 146    
 147    /** Specify encoding in first bit. Value is one. */
 148    public final static int ENCODE = 1;
 149    
 150    
 151    /** Specify decoding in first bit. Value is zero. */
 152    public final static int DECODE = 0;
 153    
 154
 155    /** Specify that data should be gzip-compressed in second bit. Value is two. */
 156    public final static int GZIP = 2;
 157
 158    /** Specify that gzipped data should <em>not</em> be automatically gunzipped. */
 159    public final static int DONT_GUNZIP = 4;
 160    
 161    
 162    /** Do break lines when encoding. Value is 8. */
 163    public final static int DO_BREAK_LINES = 8;
 164   
 165    /** 
 166     * Encode using Base64-like encoding that is URL- and Filename-safe as described
 167     * in Section 4 of RFC3548: 
 168     * <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
 169     * It is important to note that data encoded this way is <em>not</em> officially valid Base64, 
 170     * or at the very least should not be called Base64 without also specifying that is
 171     * was encoded using the URL- and Filename-safe dialect.
 172     */
 173     public final static int URL_SAFE = 16;
 174
 175
 176     /**
 177      * Encode using the special "ordered" dialect of Base64 described here:
 178      * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
 179      */
 180     public final static int ORDERED = 32;
 181    
 182    
 183/* ********  P R I V A T E   F I E L D S  ******** */  
 184    
 185    
 186    /** Maximum line length (76) of Base64 output. */
 187    private final static int MAX_LINE_LENGTH = 76;
 188    
 189    
 190    /** The equals sign (=) as a byte. */
 191    private final static byte EQUALS_SIGN = (byte)'=';
 192    
 193    
 194    /** The new line character (\n) as a byte. */
 195    private final static byte NEW_LINE = (byte)'\n';
 196    
 197    
 198    /** Preferred encoding. */
 199    private final static String PREFERRED_ENCODING = "US-ASCII";
 200    
 201   
 202    private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding
 203    private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding
 204   
 205   
 206/* ********  S T A N D A R D   B A S E 6 4   A L P H A B E T  ******** */  
 207    
 208    /** The 64 valid Base64 values. */
 209    /* Host platform me be something funny like EBCDIC, so we hardcode these values. */
 210    private final static byte[] _STANDARD_ALPHABET = {
 211        (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
 212        (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
 213        (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', 
 214        (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
 215        (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
 216        (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
 217        (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', 
 218        (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
 219        (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', 
 220        (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'+', (byte)'/'
 221    };
 222   
 223    
 224    /** 
 225     * Translates a Base64 value to either its 6-bit reconstruction value
 226     * or a negative number indicating some other meaning.
 227     **/
 228    private final static byte[] _STANDARD_DECODABET = {
 229        -9,-9,-9,-9,-9,-9,-9,-9,-9,                 // Decimal  0 -  8
 230        -5,-5,                                      // Whitespace: Tab and Linefeed
 231        -9,-9,                                      // Decimal 11 - 12
 232        -5,                                         // Whitespace: Carriage Return
 233        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 14 - 26
 234        -9,-9,-9,-9,-9,                             // Decimal 27 - 31
 235        -5,                                         // Whitespace: Space
 236        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,              // Decimal 33 - 42
 237        62,                                         // Plus sign at decimal 43
 238        -9,-9,-9,                                   // Decimal 44 - 46
 239        63,                                         // Slash at decimal 47
 240        52,53,54,55,56,57,58,59,60,61,              // Numbers zero through nine
 241        -9,-9,-9,                                   // Decimal 58 - 60
 242        -1,                                         // Equals sign at decimal 61
 243        -9,-9,-9,                                      // Decimal 62 - 64
 244        0,1,2,3,4,5,6,7,8,9,10,11,12,13,            // Letters 'A' through 'N'
 245        14,15,16,17,18,19,20,21,22,23,24,25,        // Letters 'O' through 'Z'
 246        -9,-9,-9,-9,-9,-9,                          // Decimal 91 - 96
 247        26,27,28,29,30,31,32,33,34,35,36,37,38,     // Letters 'a' through 'm'
 248        39,40,41,42,43,44,45,46,47,48,49,50,51,     // Letters 'n' through 'z'
 249        -9,-9,-9,-9                                 // Decimal 123 - 126
 250        /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 127 - 139
 251        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 140 - 152
 252        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 153 - 165
 253        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 166 - 178
 254        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 179 - 191
 255        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 192 - 204
 256        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 205 - 217
 257        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 218 - 230
 258        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 231 - 243
 259        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9         // Decimal 244 - 255 */
 260    };
 261   
 262   
 263/* ********  U R L   S A F E   B A S E 6 4   A L P H A B E T  ******** */
 264   
 265    /**
 266     * Used in the URL- and Filename-safe dialect described in Section 4 of RFC3548: 
 267     * <a href="http://www.faqs.org/rfcs/rfc3548.html">http://www.faqs.org/rfcs/rfc3548.html</a>.
 268     * Notice that the last two bytes become "hyphen" and "underscore" instead of "plus" and "slash."
 269     */
 270    private final static byte[] _URL_SAFE_ALPHABET = {
 271      (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
 272      (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
 273      (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U', 
 274      (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
 275      (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
 276      (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
 277      (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u', 
 278      (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z',
 279      (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', 
 280      (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'-', (byte)'_'
 281    };
 282   
 283    /**
 284     * Used in decoding URL- and Filename-safe dialects of Base64.
 285     */
 286    private final static byte[] _URL_SAFE_DECODABET = {
 287      -9,-9,-9,-9,-9,-9,-9,-9,-9,                 // Decimal  0 -  8
 288      -5,-5,                                      // Whitespace: Tab and Linefeed
 289      -9,-9,                                      // Decimal 11 - 12
 290      -5,                                         // Whitespace: Carriage Return
 291      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 14 - 26
 292      -9,-9,-9,-9,-9,                             // Decimal 27 - 31
 293      -5,                                         // Whitespace: Space
 294      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,              // Decimal 33 - 42
 295      -9,                                         // Plus sign at decimal 43
 296      -9,                                         // Decimal 44
 297      62,                                         // Minus sign at decimal 45
 298      -9,                                         // Decimal 46
 299      -9,                                         // Slash at decimal 47
 300      52,53,54,55,56,57,58,59,60,61,              // Numbers zero through nine
 301      -9,-9,-9,                                   // Decimal 58 - 60
 302      -1,                                         // Equals sign at decimal 61
 303      -9,-9,-9,                                   // Decimal 62 - 64
 304      0,1,2,3,4,5,6,7,8,9,10,11,12,13,            // Letters 'A' through 'N'
 305      14,15,16,17,18,19,20,21,22,23,24,25,        // Letters 'O' through 'Z'
 306      -9,-9,-9,-9,                                // Decimal 91 - 94
 307      63,                                         // Underscore at decimal 95
 308      -9,                                         // Decimal 96
 309      26,27,28,29,30,31,32,33,34,35,36,37,38,     // Letters 'a' through 'm'
 310      39,40,41,42,43,44,45,46,47,48,49,50,51,     // Letters 'n' through 'z'
 311      -9,-9,-9,-9                                 // Decimal 123 - 126
 312      /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 127 - 139
 313      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 140 - 152
 314      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 153 - 165
 315      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 166 - 178
 316      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 179 - 191
 317      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 192 - 204
 318      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 205 - 217
 319      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 218 - 230
 320      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 231 - 243
 321      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9         // Decimal 244 - 255 */
 322    };
 323
 324
 325
 326/* ********  O R D E R E D   B A S E 6 4   A L P H A B E T  ******** */
 327
 328    /**
 329     * I don't get the point of this technique, but someone requested it,
 330     * and it is described here:
 331     * <a href="http://www.faqs.org/qa/rfcc-1940.html">http://www.faqs.org/qa/rfcc-1940.html</a>.
 332     */
 333    private final static byte[] _ORDERED_ALPHABET = {
 334      (byte)'-',
 335      (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4',
 336      (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9',
 337      (byte)'A', (byte)'B', (byte)'C', (byte)'D', (byte)'E', (byte)'F', (byte)'G',
 338      (byte)'H', (byte)'I', (byte)'J', (byte)'K', (byte)'L', (byte)'M', (byte)'N',
 339      (byte)'O', (byte)'P', (byte)'Q', (byte)'R', (byte)'S', (byte)'T', (byte)'U',
 340      (byte)'V', (byte)'W', (byte)'X', (byte)'Y', (byte)'Z',
 341      (byte)'_',
 342      (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f', (byte)'g',
 343      (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m', (byte)'n',
 344      (byte)'o', (byte)'p', (byte)'q', (byte)'r', (byte)'s', (byte)'t', (byte)'u',
 345      (byte)'v', (byte)'w', (byte)'x', (byte)'y', (byte)'z'
 346    };
 347   
 348    /**
 349     * Used in decoding the "ordered" dialect of Base64.
 350     */
 351    private final static byte[] _ORDERED_DECODABET = {
 352      -9,-9,-9,-9,-9,-9,-9,-9,-9,                 // Decimal  0 -  8
 353      -5,-5,                                      // Whitespace: Tab and Linefeed
 354      -9,-9,                                      // Decimal 11 - 12
 355      -5,                                         // Whitespace: Carriage Return
 356      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 14 - 26
 357      -9,-9,-9,-9,-9,                             // Decimal 27 - 31
 358      -5,                                         // Whitespace: Space
 359      -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,              // Decimal 33 - 42
 360      -9,                                         // Plus sign at decimal 43
 361      -9,                                         // Decimal 44
 362      0,                                          // Minus sign at decimal 45
 363      -9,                                         // Decimal 46
 364      -9,                                         // Slash at decimal 47
 365      1,2,3,4,5,6,7,8,9,10,                       // Numbers zero through nine
 366      -9,-9,-9,                                   // Decimal 58 - 60
 367      -1,                                         // Equals sign at decimal 61
 368      -9,-9,-9,                                   // Decimal 62 - 64
 369      11,12,13,14,15,16,17,18,19,20,21,22,23,     // Letters 'A' through 'M'
 370      24,25,26,27,28,29,30,31,32,33,34,35,36,     // Letters 'N' through 'Z'
 371      -9,-9,-9,-9,                                // Decimal 91 - 94
 372      37,                                         // Underscore at decimal 95
 373      -9,                                         // Decimal 96
 374      38,39,40,41,42,43,44,45,46,47,48,49,50,     // Letters 'a' through 'm'
 375      51,52,53,54,55,56,57,58,59,60,61,62,63,     // Letters 'n' through 'z'
 376      -9,-9,-9,-9                                 // Decimal 123 - 126
 377      /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 127 - 139
 378        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 140 - 152
 379        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 153 - 165
 380        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 166 - 178
 381        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 179 - 191
 382        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 192 - 204
 383        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 205 - 217
 384        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 218 - 230
 385        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 231 - 243
 386        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9         // Decimal 244 - 255 */
 387    };
 388
 389   
 390/* ********  D E T E R M I N E   W H I C H   A L H A B E T  ******** */
 391
 392
 393    /**
 394     * Returns one of the _SOMETHING_ALPHABET byte arrays depending on
 395     * the options specified.
 396     * It's possible, though silly, to specify ORDERED <b>and</b> URLSAFE
 397     * in which case one of them will be picked, though there is
 398     * no guarantee as to which one will be picked.
 399     */
 400    private final static byte[] getAlphabet( int options ) {
 401        if ((options & URL_SAFE) == URL_SAFE) {
 402            return _URL_SAFE_ALPHABET;
 403        } else if ((options & ORDERED) == ORDERED) {
 404            return _ORDERED_ALPHABET;
 405        } else {
 406            return _STANDARD_ALPHABET;
 407        }
 408    } // end getAlphabet
 409
 410
 411    /**
 412     * Returns one of the _SOMETHING_DECODABET byte arrays depending on
 413     * the options specified.
 414     * It's possible, though silly, to specify ORDERED and URL_SAFE
 415     * in which case one of them will be picked, though there is
 416     * no guarantee as to which one will be picked.
 417     */
 418    private final static byte[] getDecodabet( int options ) {
 419        if( (options & URL_SAFE) == URL_SAFE) {
 420            return _URL_SAFE_DECODABET;
 421        } else if ((options & ORDERED) == ORDERED) {
 422            return _ORDERED_DECODABET;
 423        } else {
 424            return _STANDARD_DECODABET;
 425        }
 426    } // end getAlphabet
 427
 428
 429    
 430    /** Defeats instantiation. */
 431    private Base64(){}
 432    
 433
 434    
 435    
 436/* ********  E N C O D I N G   M E T H O D S  ******** */    
 437    
 438    
 439    /**
 440     * Encodes up to the first three bytes of array <var>threeBytes</var>
 441     * and returns a four-byte array in Base64 notation.
 442     * The actual number of significant bytes in your array is
 443     * given by <var>numSigBytes</var>.
 444     * The array <var>threeBytes</var> needs only be as big as
 445     * <var>numSigBytes</var>.
 446     * Code can reuse a byte array by passing a four-byte array as <var>b4</var>.
 447     *
 448     * @param b4 A reusable byte array to reduce array instantiation
 449     * @param threeBytes the array to convert
 450     * @param numSigBytes the number of significant bytes in your array
 451     * @return four byte array in Base64 notation.
 452     * @since 1.5.1
 453     */
 454    private static byte[] encode3to4( byte[] b4, byte[] threeBytes, int numSigBytes, int options ) {
 455        encode3to4( threeBytes, 0, numSigBytes, b4, 0, options );
 456        return b4;
 457    }   // end encode3to4
 458
 459    
 460    /**
 461     * <p>Encodes up to three bytes of the array <var>source</var>
 462     * and writes the resulting four Base64 bytes to <var>destination</var>.
 463     * The source and destination arrays can be manipulated
 464     * anywhere along their length by specifying 
 465     * <var>srcOffset</var> and <var>destOffset</var>.
 466     * This method does not check to make sure your arrays
 467     * are large enough to accomodate <var>srcOffset</var> + 3 for
 468     * the <var>source</var> array or <var>destOffset</var> + 4 for
 469     * the <var>destination</var> array.
 470     * The actual number of significant bytes in your array is
 471     * given by <var>numSigBytes</var>.</p>
 472    * <p>This is the lowest level of the encoding methods with
 473    * all possible parameters.</p>
 474     *
 475     * @param source the array to convert
 476     * @param srcOffset the index where conversion begins
 477     * @param numSigBytes the number of significant bytes in your array
 478     * @param destination the array to hold the conversion
 479     * @param destOffset the index where output will be put
 480     * @return the <var>destination</var> array
 481     * @since 1.3
 482     */
 483    private static byte[] encode3to4( 
 484    byte[] source, int srcOffset, int numSigBytes,
 485    byte[] destination, int destOffset, int options ) {
 486        
 487   byte[] ALPHABET = getAlphabet( options ); 
 488   
 489        //           1         2         3  
 490        // 01234567890123456789012345678901 Bit position
 491        // --------000000001111111122222222 Array position from threeBytes
 492        // --------|    ||    ||    ||    | Six bit groups to index ALPHABET
 493        //          >>18  >>12  >> 6  >> 0  Right shift necessary
 494        //                0x3f  0x3f  0x3f  Additional AND
 495        
 496        // Create buffer with zero-padding if there are only one or two
 497        // significant bytes passed in the array.
 498        // We have to shift left 24 in order to flush out the 1's that appear
 499        // when Java treats a value as negative that is cast from a byte to an int.
 500        int inBuff =   ( numSigBytes > 0 ? ((source[ srcOffset     ] << 24) >>>  8) : 0 )
 501                     | ( numSigBytes > 1 ? ((source[ srcOffset + 1 ] << 24) >>> 16) : 0 )
 502                     | ( numSigBytes > 2 ? ((source[ srcOffset + 2 ] << 24) >>> 24) : 0 );
 503
 504        switch( numSigBytes )
 505        {
 506            case 3:
 507                destination[ destOffset     ] = ALPHABET[ (inBuff >>> 18)        ];
 508                destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
 509                destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>>  6) & 0x3f ];
 510                destination[ destOffset + 3 ] = ALPHABET[ (inBuff       ) & 0x3f ];
 511                return destination;
 512                
 513            case 2:
 514                destination[ destOffset     ] = ALPHABET[ (inBuff >>> 18)        ];
 515                destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
 516                destination[ destOffset + 2 ] = ALPHABET[ (inBuff >>>  6) & 0x3f ];
 517                destination[ destOffset + 3 ] = EQUALS_SIGN;
 518                return destination;
 519                
 520            case 1:
 521                destination[ destOffset     ] = ALPHABET[ (inBuff >>> 18)        ];
 522                destination[ destOffset + 1 ] = ALPHABET[ (inBuff >>> 12) & 0x3f ];
 523                destination[ destOffset + 2 ] = EQUALS_SIGN;
 524                destination[ destOffset + 3 ] = EQUALS_SIGN;
 525                return destination;
 526                
 527            default:
 528                return destination;
 529        }   // end switch
 530    }   // end encode3to4
 531
 532
 533
 534    /**
 535     * Performs Base64 encoding on the <code>raw</code> ByteBuffer,
 536     * writing it to the <code>encoded</code> ByteBuffer.
 537     * This is an experimental feature. Currently it does not
 538     * pass along any options (such as {@link #DO_BREAK_LINES}
 539     * or {@link #GZIP}.
 540     *
 541     * @param raw input buffer
 542     * @param encoded output buffer
 543     * @since 2.3
 544     */
 545    public static void encode( java.nio.ByteBuffer raw, java.nio.ByteBuffer encoded ){
 546        byte[] raw3 = new byte[3];
 547        byte[] enc4 = new byte[4];
 548
 549        while( raw.hasRemaining() ){
 550            int rem = Math.min(3,raw.remaining());
 551            raw.get(raw3,0,rem);
 552            Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS );
 553            encoded.put(enc4);
 554        }   // end input remaining
 555    }
 556
 557
 558    /**
 559     * Performs Base64 encoding on the <code>raw</code> ByteBuffer,
 560     * writing it to the <code>encoded</code> CharBuffer.
 561     * This is an experimental feature. Currently it does not
 562     * pass along any options (such as {@link #DO_BREAK_LINES}
 563     * or {@link #GZIP}.
 564     *
 565     * @param raw input buffer
 566     * @param encoded output buffer
 567     * @since 2.3
 568     */
 569    public static void encode( java.nio.ByteBuffer raw, java.nio.CharBuffer encoded ){
 570        byte[] raw3 = new byte[3];
 571        byte[] enc4 = new byte[4];
 572
 573        while( raw.hasRemaining() ){
 574            int rem = Math.min(3,raw.remaining());
 575            raw.get(raw3,0,rem);
 576            Base64.encode3to4(enc4, raw3, rem, Base64.NO_OPTIONS );
 577            for( int i = 0; i < 4; i++ ){
 578                encoded.put( (char)(enc4[i] & 0xFF) );
 579            }
 580        }   // end input remaining
 581    }
 582
 583
 584    
 585    
 586    /**
 587     * Serializes an object and returns the Base64-encoded
 588     * version of that serialized object.  
 589     *  
 590     * <p>As of v 2.3, if the object
 591     * cannot be serialized or there is another error,
 592     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
 593     * In earlier versions, it just returned a null value, but
 594     * in retrospect that's a pretty poor way to handle it.</p>
 595     * 
 596     * The object is not GZip-compressed before being encoded.
 597     *
 598     * @param serializableObject The object to encode
 599     * @return The Base64-encoded object
 600     * @throws java.io.IOException if there is an error
 601     * @throws NullPointerException if serializedObject is null
 602     * @since 1.4
 603     */
 604    public static String encodeObject( java.io.Serializable serializableObject )
 605    throws java.io.IOException {
 606        return encodeObject( serializableObject, NO_OPTIONS );
 607    }   // end encodeObject
 608    
 609
 610
 611    /**
 612     * Serializes an object and returns the Base64-encoded
 613     * version of that serialized object.
 614     *  
 615     * <p>As of v 2.3, if the object
 616     * cannot be serialized or there is another error,
 617     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
 618     * In earlier versions, it just returned a null value, but
 619     * in retrospect that's a pretty poor way to handle it.</p>
 620     * 
 621     * The object is not GZip-compressed before being encoded.
 622     * <p>
 623     * Example options:<pre>
 624     *   GZIP: gzip-compresses object before encoding it.
 625     *   DO_BREAK_LINES: break lines at 76 characters
 626     * </pre>
 627     * <p>
 628     * Example: <code>encodeObject( myObj, Base64.GZIP )</code> or
 629     * <p>
 630     * Example: <code>encodeObject( myObj, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
 631     *
 632     * @param serializableObject The object to encode
 633     * @param options Specified options
 634     * @return The Base64-encoded object
 635     * @see Base64#GZIP
 636     * @see Base64#DO_BREAK_LINES
 637     * @throws java.io.IOException if there is an error
 638     * @since 2.0
 639     */
 640    public static String encodeObject( java.io.Serializable serializableObject, int options )
 641    throws java.io.IOException {
 642
 643        if( serializableObject == null ){
 644            throw new NullPointerException( "Cannot serialize a null object." );
 645        }   // end if: null
 646        
 647        // Streams
 648        java.io.ByteArrayOutputStream  baos  = null; 
 649        java.io.OutputStream           b64os = null;
 650        java.util.zip.GZIPOutputStream gzos  = null;
 651        java.io.ObjectOutputStream     oos   = null;
 652        
 653        
 654        try {
 655            // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream
 656            baos  = new java.io.ByteArrayOutputStream();
 657            b64os = new Base64.OutputStream( baos, ENCODE | options );
 658            if( (options & GZIP) != 0 ){
 659                // Gzip
 660                gzos = new java.util.zip.GZIPOutputStream(b64os);
 661                oos = new java.io.ObjectOutputStream( gzos );
 662            } else {
 663                // Not gzipped
 664                oos = new java.io.ObjectOutputStream( b64os );
 665            }
 666            oos.writeObject( serializableObject );
 667        }   // end try
 668        catch( java.io.IOException e ) {
 669            // Catch it and then throw it immediately so that
 670            // the finally{} block is called for cleanup.
 671            throw e;
 672        }   // end catch
 673        finally {
 674            try{ oos.close();   } catch( Exception e ){}
 675            try{ gzos.close();  } catch( Exception e ){}
 676            try{ b64os.close(); } catch( Exception e ){}
 677            try{ baos.close();  } catch( Exception e ){}
 678        }   // end finally
 679        
 680        // Return value according to relevant encoding.
 681        try {
 682            return new String( baos.toByteArray(), PREFERRED_ENCODING );
 683        }   // end try
 684        catch (java.io.UnsupportedEncodingException uue){
 685            // Fall back to some Java default
 686            return new String( baos.toByteArray() );
 687        }   // end catch
 688        
 689    }   // end encode
 690    
 691    
 692
 693    /**
 694     * Encodes a byte array into Base64 notation.
 695     * Does not GZip-compress data.
 696     *  
 697     * @param source The data to convert
 698     * @return The data in Base64-encoded form
 699     * @throws NullPointerException if source array is null
 700     * @since 1.4
 701     */
 702    public static String encodeBytes( byte[] source ) {
 703        // Since we're not going to have the GZIP encoding turned on,
 704        // we're not going to have an java.io.IOException thrown, so
 705        // we should not force the user to have to catch it.
 706        String encoded = null;
 707        try {
 708            encoded = encodeBytes(source, 0, source.length, NO_OPTIONS);
 709        } catch (java.io.IOException ex) {
 710            assert false : ex.getMessage();
 711        }   // end catch
 712        assert encoded != null;
 713        return encoded;
 714    }   // end encodeBytes
 715    
 716
 717
 718    /**
 719     * Encodes a byte array into Base64 notation.
 720     * <p>
 721     * Example options:<pre>
 722     *   GZIP: gzip-compresses object before encoding it.
 723     *   DO_BREAK_LINES: break lines at 76 characters
 724     *     <i>Note: Technically, this makes your encoding non-compliant.</i>
 725     * </pre>
 726     * <p>
 727     * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
 728     * <p>
 729     * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
 730     *
 731     *  
 732     * <p>As of v 2.3, if there is an error with the GZIP stream,
 733     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
 734     * In earlier versions, it just returned a null value, but
 735     * in retrospect that's a pretty poor way to handle it.</p>
 736     * 
 737     *
 738     * @param source The data to convert
 739     * @param options Specified options
 740     * @return The Base64-encoded data as a String
 741     * @see Base64#GZIP
 742     * @see Base64#DO_BREAK_LINES
 743     * @throws java.io.IOException if there is an error
 744     * @throws NullPointerException if source array is null
 745     * @since 2.0
 746     */
 747    public static String encodeBytes( byte[] source, int options ) throws java.io.IOException {
 748        return encodeBytes( source, 0, source.length, options );
 749    }   // end encodeBytes
 750    
 751    
 752    /**
 753     * Encodes a byte array into Base64 notation.
 754     * Does not GZip-compress data.
 755     *  
 756     * <p>As of v 2.3, if there is an error,
 757     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
 758     * In earlier versions, it just returned a null value, but
 759     * in retrospect that's a pretty poor way to handle it.</p>
 760     * 
 761     *
 762     * @param source The data to convert
 763     * @param off Offset in array where conversion should begin
 764     * @param len Length of data to convert
 765     * @return The Base64-encoded data as a String
 766     * @throws NullPointerException if source array is null
 767     * @throws IllegalArgumentException if source array, offset, or length are invalid
 768     * @since 1.4
 769     */
 770    public static String encodeBytes( byte[] source, int off, int len ) {
 771        // Since we're not going to have the GZIP encoding turned on,
 772        // we're not going to have an java.io.IOException thrown, so
 773        // we should not force the user to have to catch it.
 774        String encoded = null;
 775        try {
 776            encoded = encodeBytes( source, off, len, NO_OPTIONS );
 777        } catch (java.io.IOException ex) {
 778            assert false : ex.getMessage();
 779        }   // end catch
 780        assert encoded != null;
 781        return encoded;
 782    }   // end encodeBytes
 783    
 784    
 785
 786    /**
 787     * Encodes a byte array into Base64 notation.
 788     * <p>
 789     * Example options:<pre>
 790     *   GZIP: gzip-compresses object before encoding it.
 791     *   DO_BREAK_LINES: break lines at 76 characters
 792     *     <i>Note: Technically, this makes your encoding non-compliant.</i>
 793     * </pre>
 794     * <p>
 795     * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
 796     * <p>
 797     * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DO_BREAK_LINES )</code>
 798     *
 799     *  
 800     * <p>As of v 2.3, if there is an error with the GZIP stream,
 801     * the method will throw an java.io.IOException. <b>This is new to v2.3!</b>
 802     * In earlier versions, it just returned a null value, but
 803     * in retrospect that's a pretty poor way to handle it.</p>
 804     * 
 805     *
 806     * @param source The data to convert
 807     * @param off Offset in array where conversion should begin
 808     * @param len Length of data to convert
 809     * @param options Specified options
 810     * @return The Base64-encoded data as a String
 811     * @see Base64#GZIP
 812     * @see Base64#DO_BREAK_LINES
 813     * @throws java.io.IOException if there is an error
 814     * @throws NullPointerException if source array is null
 815     * @throws IllegalArgumentException if source array, offset, or length are invalid
 816     * @since 2.0
 817     */
 818    public static String encodeBytes( byte[] source, int off, int len, int options ) throws java.io.IOException {
 819        byte[] encoded = encodeBytesToBytes( source, off, len, options );
 820
 821        // Return value according to relevant encoding.
 822        try {
 823            return new String( encoded, PREFERRED_ENCODING );
 824        }   // end try
 825        catch (java.io.UnsupportedEncodingException uue) {
 826            return new String( encoded );
 827        }   // end catch
 828        
 829    }   // end encodeBytes
 830
 831
 832
 833
 834    /**
 835     * Similar to {@link #encodeBytes(byte[])} but returns
 836     * a byte array instead of instantiating a String. This is more efficient
 837     * if you're working with I/O streams and have large data sets to encode.
 838     *
 839     *
 840     * @param source The data to convert
 841     * @return The Base64-encoded data as a byte[] (of ASCII characters)
 842     * @throws NullPointerException if source array is null
 843     * @since 2.3.1
 844     */
 845    public static byte[] encodeBytesToBytes( byte[] source ) {
 846        byte[] encoded = null;
 847        try {
 848            encoded = encodeBytesToBytes( source, 0, source.length, Base64.NO_OPTIONS );
 849        } catch( java.io.IOException ex ) {
 850            assert false : "IOExceptions only come from GZipping, which is turned off: " + ex.getMessage();
 851        }
 852        return encoded;
 853    }
 854
 855
 856    /**
 857     * Similar to {@link #encodeBytes(byte[], int, int, int)} but returns
 858     * a byte array instead of instantiating a String. This is more efficient
 859     * if you're working with I/O streams and have large data sets to encode.
 860     *
 861     *
 862     * @param source The data to convert
 863     * @param off Offset in array where conversion should begin
 864     * @param len Length of data to convert
 865     * @param options Specified options
 866     * @return The Base64-encoded data as a String
 867     * @see Base64#GZIP
 868     * @see Base64#DO_BREAK_LINES
 869     * @throws java.io.IOException if there is an error
 870     * @throws NullPointerException if source array is null
 871     * @throws IllegalArgumentException if source array, offset, or length are invalid
 872     * @since 2.3.1
 873     */
 874    public static byte[] encodeBytesToBytes( byte[] source, int off, int len, int options ) throws java.io.IOException {
 875
 876        if( source == null ){
 877            throw new NullPointerException( "Cannot serialize a null array." );
 878        }   // end if: null
 879
 880        if( off < 0 ){
 881            throw new IllegalArgumentException( "Cannot have negative offset: " + off );
 882        }   // end if: off < 0
 883
 884        if( len < 0 ){
 885            throw new IllegalArgumentException( "Cannot have length offset: " + len );
 886        }   // end if: len < 0
 887
 888        if( off + len > source.length  ){
 889            throw new IllegalArgumentException(
 890            String.format( "Cannot have offset of %d and length of %d with array of length %d", off,len,source.length));
 891        }   // end if: off < 0
 892
 893
 894
 895        // Compress?
 896        if( (options & GZIP) != 0 ) {
 897            java.io.ByteArrayOutputStream  baos  = null;
 898            java.util.zip.GZIPOutputStream gzos  = null;
 899            Base64.OutputStream            b64os = null;
 900
 901            try {
 902                // GZip -> Base64 -> ByteArray
 903                baos = new java.io.ByteArrayOutputStream();
 904                b64os = new Base64.OutputStream( baos, ENCODE | options );
 905                gzos  = new java.util.zip.GZIPOutputStream( b64os );
 906
 907                gzos.write( source, off, len );
 908                gzos.close();
 909            }   // end try
 910            catch( java.io.IOException e ) {
 911                // Catch it and then throw it immediately so that
 912                // the finally{} block is called for cleanup.
 913                throw e;
 914            }   // end catch
 915            finally {
 916                try{ gzos.close();  } catch( Exception e ){}
 917                try{ b64os.close(); } catch( Exception e ){}
 918                try{ baos.close();  } catch( Exception e ){}
 919            }   // end finally
 920
 921            return baos.toByteArray();
 922        }   // end if: compress
 923
 924        // Else, don't compress. Better not to use streams at all then.
 925        else {
 926            boolean breakLines = (options & DO_BREAK_LINES) > 0;
 927
 928            //int    len43   = len * 4 / 3;
 929            //byte[] outBuff = new byte[   ( len43 )                      // Main 4:3
 930            //                           + ( (len % 3) > 0 ? 4 : 0 )      // Account for padding
 931            //                           + (breakLines ? ( len43 / MAX_LINE_LENGTH ) : 0) ]; // New lines
 932            // Try to determine more precisely how big the array needs to be.
 933            // If we get it right, we don't have to do an array copy, and
 934            // we save a bunch of memory.
 935            int encLen = ( len / 3 ) * 4 + ( len % 3 > 0 ? 4 : 0 ); // Bytes needed for actual encoding
 936            if( breakLines ){
 937                encLen += encLen / MAX_LINE_LENGTH; // Plus extra newline characters
 938            }
 939            byte[] outBuff = new byte[ encLen ];
 940
 941
 942            int d = 0;
 943            int e = 0;
 944            int len2 = len - 2;
 945            int lineLength = 0;
 946            for( ; d < len2; d+=3, e+=4 ) {
 947                encode3to4( source, d+off, 3, outBuff, e, options );
 948
 949                lineLength += 4;
 950                if( breakLines && lineLength >= MAX_LINE_LENGTH )
 951                {
 952                    outBuff[e+4] = NEW_LINE;
 953                    e++;
 954                    lineLength = 0;
 955                }   // end if: end of line
 956            }   // en dfor: each piece of array
 957
 958            if( d < len ) {
 959                encode3to4( source, d+off, len - d, outBuff, e, options );
 960                e += 4;
 961            }   // end if: some padding needed
 962
 963
 964            // Only resize array if we didn't guess it right.
 965            if( e < outBuff.length - 1 ){
 966                byte[] finalOut = new byte[e];
 967                System.arraycopy(outBuff,0, finalOut,0,e);
 968                //System.err.println("Having to resize array from " + outBuff.length + " to " + e );
 969                return finalOut;
 970            } else {
 971                //System.err.println("No need to resize array.");
 972                return outBuff;
 973            }
 974        
 975        }   // end else: don't compress
 976
 977    }   // end encodeBytesToBytes
 978    
 979
 980    
 981    
 982    
 983/* ********  D E C O D I N G   M E T H O D S  ******** */
 984    
 985    
 986    /**
 987     * Decodes four bytes from array <var>source</var>
 988     * and writes the resulting bytes (up to three of them)
 989     * to <var>destination</var>.
 990     * The source and destination arrays can be manipulated
 991     * anywhere along their length by specifying 
 992     * <var>srcOffset</var> and <var>destOffset</var>.
 993     * This method does not check to make sure your arrays
 994     * are large enough to accomodate <var>srcOffset</var> + 4 for
 995     * the <var>source</var> array or <var>destOffset</var> + 3 for
 996     * the <var>destination</var> array.
 997     * This method returns the actual number of bytes that 
 998     * were converted from the Base64 encoding.
 999    * <p>This is the lowest level of the decoding methods with
1000    * all possible parameters.</p>
1001     * 
1002     *
1003     * @param source the array to convert
1004     * @param srcOffset the index where conversion begins
1005     * @param destination the array to hold the conversion
1006     * @param destOffset the index where output will be put
1007    * @param options alphabet type is pulled from this (standard, url-safe, ordered)
1008     * @return the number of decoded bytes converted
1009     * @throws NullPointerException if source or destination arrays are null
1010     * @throws IllegalArgumentException if srcOffset or destOffset are invalid
1011     *         or there is not enough room in the array.
1012     * @since 1.3
1013     */
1014    private static int decode4to3( 
1015    byte[] source, int srcOffset, 
1016    byte[] destination, int destOffset, int options ) {
1017        
1018        // Lots of error checking and exception throwing
1019        if( source == null ){
1020            throw new NullPointerException( "Source array was null." );
1021        }   // end if
1022        if( destination == null ){
1023            throw new NullPointerException( "Destination array was null." );
1024        }   // end if
1025        if( srcOffset < 0 || srcOffset + 3 >= source.length ){
1026            throw new IllegalArgumentException( String.format(
1027            "Source array with length %d cannot have offset of %d and still process four bytes.", source.length, srcOffset ) );
1028        }   // end if
1029        if( destOffset < 0 || destOffset +2 >= destination.length ){
1030            throw new IllegalArgumentException( String.format(
1031            "Destination array with length %d cannot have offset of %d and still store three bytes.", destination.length, destOffset ) );
1032        }   // end if
1033        
1034        
1035        byte[] DECODABET = getDecodabet( options ); 
1036   
1037        // Example: Dk==
1038        if( source[ srcOffset + 2] == EQUALS_SIGN ) {
1039            // Two ways to do the same thing. Don't know which way I like best.
1040          //int outBuff =   ( ( DECODABET[ source[ srcOffset    ] ] << 24 ) >>>  6 )
1041          //              | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );
1042            int outBuff =   ( ( DECODABET[ source[ srcOffset    ] ] & 0xFF ) << 18 )
1043                          | ( ( DECODABET[ source[ srcOffset + 1] ] & 0xFF ) << 12 );
1044            
1045            destination[ destOffset ] = (byte)( outBuff >>> 16 );
1046            return 1;
1047        }
1048        
1049        // Example: DkL=
1050        else if( source[ srcOffset + 3 ] == EQUALS_SIGN ) {
1051            // Two ways to do the same thing. Don't know which way I like best.
1052          //int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] << 24 ) >>>  6 )
1053          //              | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
1054          //              | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 );
1055            int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] & 0xFF ) << 18 )
1056                          | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
1057                          | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) <<  6 );
1058            
1059            destination[ destOffset     ] = (byte)( outBuff >>> 16 );
1060            destination[ destOffset + 1 ] = (byte)( outBuff >>>  8 );
1061            return 2;
1062        }
1063        
1064        // Example: DkLE
1065        else {
1066            // Two ways to do the same thing. Don't know which way I like best.
1067          //int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] << 24 ) >>>  6 )
1068          //              | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
1069          //              | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 )
1070          //              | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 );
1071            int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] & 0xFF ) << 18 )
1072                          | ( ( DECODABET[ source[ srcOffset + 1 ] ] & 0xFF ) << 12 )
1073                          | ( ( DECODABET[ source[ srcOffset + 2 ] ] & 0xFF ) <<  6)
1074                          | ( ( DECODABET[ source[ srcOffset + 3 ] ] & 0xFF )      );
1075
1076            
1077            destination[ destOffset     ] = (byte)( outBuff >> 16 );
1078            destination[ destOffset + 1 ] = (byte)( outBuff >>  8 );
1079            destination[ destOffset + 2 ] = (byte)( outBuff       );
1080
1081            return 3;
1082        }
1083    }   // end decodeToBytes
1084    
1085
1086
1087
1088
1089    /**
1090     * Low-level access to decoding ASCII characters in
1091     * the form of a byte array. <strong>Ignores GUNZIP option, if
1092     * it's set.</strong> This is not generally a recommended method,
1093     * although it is used internally as part of the decoding process.
1094     * Special case: if len = 0, an empty array is returned. Still,
1095     * if you need more speed and reduced memory foo

Large files files are truncated, but you can click here to view the full file