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

Save This Page
Home » iText-2.1.7 » com.lowagie » text » pdf » codec » [javadoc | source]