Java/Development Class/Base64 — различия между версиями

Материал из Java эксперт
Перейти к: навигация, поиск
 
м (1 версия)
 
(нет различий)

Текущая версия на 07:07, 1 июня 2010

Содержание

A Base64 Encoder/Decoder

    
/*******************************************************************************
 * 
 * A Base64 Encoder/Decoder.
 * 
 * This class is used to encode and decode data in Base64 format as described in
 * RFC 1521.
 * 
 * <p>
 * Copyright 2003: Christian d"Heureuse, Inventec Informatik AG, Switzerland.<br>
 * License: This is "Open Source" software and released under the <br>
 * 
 * <p>
 * Version history:<br>
 * 2003-07-22 Christian d"Heureuse (chdh): Module created.<br>
 * 2005-08-11 chdh: Lincense changed from GPL to LGPL.
 * 
 ******************************************************************************/
public class Base64Coder {
  // Mapping table from 6-bit nibbles to Base64 characters.
  private static char[] map1 = new char[64];
  static {
    int i = 0;
    for (char c = "A"; c <= "Z"; c++)
      map1[i++] = c;
    for (char c = "a"; c <= "z"; c++)
      map1[i++] = c;
    for (char c = "0"; c <= "9"; c++)
      map1[i++] = c;
    map1[i++] = "+";
    map1[i++] = "/";
  }
  // Mapping table from Base64 characters to 6-bit nibbles.
  private static byte[] map2 = new byte[128];
  static {
    for (int i = 0; i < map2.length; i++)
      map2[i] = -1;
    for (int i = 0; i < 64; i++)
      map2[map1[i]] = (byte) i;
  }
  /**
   * Encodes a string into Base64 format. No blanks or line breaks are inserted.
   * 
   * @param s
   *          a String to be encoded.
   * @return A String with the Base64 encoded data.
   */
  public static String encode(String s) {
    return new String(encode(s.getBytes()));
  }
  /**
   * Encodes a byte array into Base64 format. No blanks or line breaks are
   * inserted.
   * 
   * @param in
   *          an array containing the data bytes to be encoded.
   * @return A character array with the Base64 encoded data.
   */
  public static char[] encode(byte[] in) {
    int iLen = in.length;
    int oDataLen = (iLen * 4 + 2) / 3; // output length without padding
    int oLen = ((iLen + 2) / 3) * 4; // output length including padding
    char[] out = new char[oLen];
    int ip = 0;
    int op = 0;
    while (ip < iLen) {
      int i0 = in[ip++] & 0xff;
      int i1 = ip < iLen ? in[ip++] & 0xff : 0;
      int i2 = ip < iLen ? in[ip++] & 0xff : 0;
      int o0 = i0 >>> 2;
      int o1 = ((i0 & 3) << 4) | (i1 >>> 4);
      int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6);
      int o3 = i2 & 0x3F;
      out[op++] = map1[o0];
      out[op++] = map1[o1];
      out[op] = op < oDataLen ? map1[o2] : "=";
      op++;
      out[op] = op < oDataLen ? map1[o3] : "=";
      op++;
    }
    return out;
  }
  /**
   * Decodes a Base64 string.
   * 
   * @param s
   *          a Base64 String to be decoded.
   * @return A String containing the decoded data.
   * @throws IllegalArgumentException
   *           if the input is not valid Base64 encoded data.
   */
  public static String decode(String s) {
    return new String(decode(s.toCharArray()));
  }
  /**
   * Decodes Base64 data. No blanks or line breaks are allowed within the Base64
   * encoded data.
   * 
   * @param in
   *          a character array containing the Base64 encoded data.
   * @return An array containing the decoded data bytes.
   * @throws IllegalArgumentException
   *           if the input is not valid Base64 encoded data.
   */
  public static byte[] decode(char[] in) {
    int iLen = in.length;
    if (iLen % 4 != 0)
      throw new IllegalArgumentException(
          "Length of Base64 encoded input string is not a multiple of 4.");
    while (iLen > 0 && in[iLen - 1] == "=")
      iLen--;
    int oLen = (iLen * 3) / 4;
    byte[] out = new byte[oLen];
    int ip = 0;
    int op = 0;
    while (ip < iLen) {
      int i0 = in[ip++];
      int i1 = in[ip++];
      int i2 = ip < iLen ? in[ip++] : "A";
      int i3 = ip < iLen ? in[ip++] : "A";
      if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127)
        throw new IllegalArgumentException("Illegal character in Base64 encoded data.");
      int b0 = map2[i0];
      int b1 = map2[i1];
      int b2 = map2[i2];
      int b3 = map2[i3];
      if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0)
        throw new IllegalArgumentException("Illegal character in Base64 encoded data.");
      int o0 = (b0 << 2) | (b1 >>> 4);
      int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2);
      int o2 = ((b2 & 3) << 6) | b3;
      out[op++] = (byte) o0;
      if (op < oLen)
        out[op++] = (byte) o1;
      if (op < oLen)
        out[op++] = (byte) o2;
    }
    return out;
  }
}





A fast and memory efficient class to encode and decode to and from BASE64 in full accordance with RFC 2045

    

import java.util.Arrays;
/** A very fast and memory efficient class to encode and decode to and from BASE64 in full accordance
 * with RFC 2045.<br><br>
 * On Windows XP sp1 with 1.4.2_04 and later ;), this encoder and decoder is about 10 times faster
 * on small arrays (10 - 1000 bytes) and 2-3 times as fast on larger arrays (10000 - 1000000 bytes)
 * compared to <code>sun.misc.Encoder()/Decoder()</code>.<br><br>
 *
 * On byte arrays the encoder is about 20% faster than Jakarta Commons Base64 Codec for encode and
 * about 50% faster for decoding large arrays. This implementation is about twice as fast on very small
 * arrays (&lt 30 bytes). If source/destination is a <code>String</code> this
 * version is about three times as fast due to the fact that the Commons Codec result has to be recoded
 * to a <code>String</code> from <code>byte[]</code>, which is very expensive.<br><br>
 *
 * This encode/decode algorithm doesn"t create any temporary arrays as many other codecs do, it only
 * allocates the resulting array. This produces less garbage and it is possible to handle arrays twice
 * as large as algorithms that create a temporary array. (E.g. Jakarta Commons Codec). It is unknown
 * whether Sun"s <code>sun.misc.Encoder()/Decoder()</code> produce temporary arrays but since performance
 * is quite low it probably does.<br><br>
 *
 * The encoder produces the same output as the Sun one except that the Sun"s encoder appends
 * a trailing line separator if the last character isn"t a pad. Unclear why but it only adds to the
 * length and is probably a side effect. Both are in conformance with RFC 2045 though.<br>
 * Commons codec seem to always att a trailing line separator.<br><br>
 *
 * <b>Note!</b>
 * The encode/decode method pairs (types) come in three versions with the <b>exact</b> same algorithm and
 * thus a lot of code redundancy. This is to not create any temporary arrays for transcoding to/from different
 * format types. The methods not used can simply be commented out.<br><br>
 *
 * There is also a "fast" version of all decode methods that works the same way as the normal ones, but
 * har a few demands on the decoded input. Normally though, these fast verions should be used if the source if
 * the input is known and it hasn"t bee tampered with.<br><br>
 *
 * If you find the code useful or you find a bug, please send me a note at base64 @ miginfocom . com.
 *
 * Licence (BSD):
 * 
 *
 * Copyright (c) 2004, Mikael Grev, MiG InfoCom AB. (base64 @ miginfocom . com)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright notice, this list
 * of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this
 * list of conditions and the following disclaimer in the documentation and/or other
 * materials provided with the distribution.
 * Neither the name of the MiG InfoCom AB nor the names of its contributors may be
 * used to endorse or promote products derived from this software without specific
 * prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 * OF SUCH DAMAGE.
 *
 * @version 2.2
 * @author Mikael Grev
 *         Date: 2004-aug-02
 *         Time: 11:31:11
 */
public class Base64
{
  private static final char[] CA = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
  private static final int[] IA = new int[256];
  static {
    Arrays.fill(IA, -1);
    for (int i = 0, iS = CA.length; i < iS; ++i) {
      IA[CA[i]] = i;
    }
    IA["="] = 0;
  }
  // ****************************************************************************************
  // *  char[] version
  // ****************************************************************************************
  /** Encodes a raw byte array into a BASE64 <code>char[]</code> representation i accordance with RFC 2045.
   * @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
   * @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
   * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
   * little faster.
   * @return A BASE64 encoded array. Never <code>null</code>.
   */
  public final static char[] encodeToChar(byte[] sArr, boolean lineSep)
  {
    // Check special case
    int sLen = sArr != null ? sArr.length : 0;
    if (sLen == 0) {
      return new char[0];
    }
    //assert sArr != null;
    int eLen = (sLen / 3) * 3;              // Length of even 24-bits.
    int cCnt = ((sLen - 1) / 3 + 1) << 2;   // Returned character count
    int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
    char[] dArr = new char[dLen];
    // Encode even 24-bits
    for (int s = 0, d = 0, cc = 0; s < eLen;) {
      // Copy next three bytes into lower 24 bits of int, paying attension to sign.
      int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
      // Encode the int into four chars
      dArr[d++] = CA[(i >>> 18) & 0x3f];
      dArr[d++] = CA[(i >>> 12) & 0x3f];
      dArr[d++] = CA[(i >>> 6) & 0x3f];
      dArr[d++] = CA[i & 0x3f];
      // Add optional line separator
      if (lineSep && ++cc == 19 && d < dLen - 2) {
        dArr[d++] = "\r";
        dArr[d++] = "\n";
        cc = 0;
      }
    }
    // Pad and encode last bits if source isn"t even 24 bits.
    int left = sLen - eLen; // 0 - 2.
    if (left > 0) {
      // Prepare the int
      int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);
      // Set last four chars
      dArr[dLen - 4] = CA[i >> 12];
      dArr[dLen - 3] = CA[(i >>> 6) & 0x3f];
      dArr[dLen - 2] = left == 2 ? CA[i & 0x3f] : "=";
      dArr[dLen - 1] = "=";
    }
    return dArr;
  }
  /** Decodes a BASE64 encoded char array. All illegal characters will be ignored and can handle both arrays with
   * and without line separators.
   * @param sArr The source array. <code>null</code> or length 0 will return an empty array.
   * @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
   * (including "=") isn"t divideable by 4.  (I.e. definitely corrupted).
   */
  public final static byte[] decode(char[] sArr)
  {
    // Check special case
    int sLen = sArr != null ? sArr.length : 0;
    if (sLen == 0) {
      return new byte[0];
    }
    //assert sArr != null;
    // Count illegal characters (including "\r", "\n") to know what size the returned array will be,
    // so we don"t have to reallocate & copy it later.
    int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that"s a bonus...)
    for (int i = 0; i < sLen; ++i) {
      if (IA[sArr[i]] < 0) {
        ++sepCnt;
      }
    }
    // Check so that legal chars (including "=") are evenly divideable by 4 as specified in RFC 2045.
    if ((sLen - sepCnt) % 4 != 0) {
      return null;
    }
    int pad = 0;
    for (int i = sLen; i > 1 && IA[sArr[--i]] <= 0;) {
      if (sArr[i] == "=") {
        ++pad;
      }
    }
    int len = ((sLen - sepCnt) * 6 >> 3) - pad;
    byte[] dArr = new byte[len];       // Preallocate byte[] of exact length
    for (int s = 0, d = 0; d < len;) {
      // Assemble three bytes into an int from four "valid" characters.
      int i = 0;
      for (int j = 0; j < 4; ++j) {   // j only increased if a valid char was found.
        int c = IA[sArr[s++]];
        if (c >= 0) {
          i |= c << (18 - j * 6);
        } else {
          --j;
        }
      }
      // Add the bytes
      dArr[d++] = (byte) (i >> 16);
      if (d < len) {
        dArr[d++]= (byte) (i >> 8);
        if (d < len) {
          dArr[d++] = (byte) i;
        }
      }
    }
    return dArr;
  }
  /* * Decodes a BASE64 encoded char array that is known to be resonably well formatted. The method is about twice as
   * fast as {@link #decode(char[])}. The preconditions are:<br>
   * + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
   * + Line separator must be "\r\n", as specified in RFC 2045
   * + The array must not contain illegal characters within the encoded string<br>
   * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
   * @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
   * @return The decoded array of bytes. May be of length 0.
   * /
  public final static byte[] decodeFast(char[] sArr)
  {
    // Check special case
    int sLen = sArr.length;
    if (sLen == 0) {
      return new byte[0];
    }
    int sIx = 0, eIx = sLen - 1;    // Start and end index after trimming.
    // Trim illegal chars from start
    while (sIx < eIx && IA[sArr[sIx]] < 0) {
      ++sIx;
    }
    // Trim illegal chars from end
    while (eIx > 0 && IA[sArr[eIx]] < 0) {
      --eIx;
    }
    // get the padding count (=) (0, 1 or 2)
    int pad = sArr[eIx] == "=" ? (sArr[eIx - 1] == "=" ? 2 : 1) : 0;  // Count "=" at end.
    int cCnt = eIx - sIx + 1;   // Content count including possible separators
    int sepCnt = sLen > 76 ? (sArr[76] == "\r" ? cCnt / 78 : 0) << 1 : 0;
    int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
    byte[] dArr = new byte[len];       // Preallocate byte[] of exact length
    // Decode all but the last 0 - 2 bytes.
    int d = 0;
    for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) {
      // Assemble three bytes into an int from four "valid" characters.
      int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]];
      // Add the bytes
      dArr[d++] = (byte) (i >> 16);
      dArr[d++] = (byte) (i >> 8);
      dArr[d++] = (byte) i;
      // If line separator, jump over it.
      if (sepCnt > 0 && ++cc == 19) {
        sIx += 2;
        cc = 0;
      }
    }
    if (d < len) {
      // Decode last 1-3 bytes (incl "=") into 1-3 bytes
      int i = 0;
      for (int j = 0; sIx <= eIx - pad; ++j) {
        i |= IA[sArr[sIx++]] << (18 - j * 6);
      }
      for (int r = 16; d < len; r -= 8) {
        dArr[d++] = (byte) (i >> r);
      }
    }
    return dArr;
  }*/
  // ****************************************************************************************
  // *  byte[] version
  // ****************************************************************************************
  /** Encodes a raw byte array into a BASE64 <code>byte[]</code> representation i accordance with RFC 2045.
   * @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
   * @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
   * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
   * little faster.
   * @return A BASE64 encoded array. Never <code>null</code>.
   */
  public final static byte[] encodeToByte(byte[] sArr, boolean lineSep)
  {
    // Check special case
    int sLen = sArr != null ? sArr.length : 0;
    if (sLen == 0) {
      return new byte[0];
    }
    //assert sArr != null;
    int eLen = (sLen / 3) * 3;                              // Length of even 24-bits.
    int cCnt = ((sLen - 1) / 3 + 1) << 2;                   // Returned character count
    int dLen = cCnt + (lineSep ? (cCnt - 1) / 76 << 1 : 0); // Length of returned array
    byte[] dArr = new byte[dLen];
    // Encode even 24-bits
    for (int s = 0, d = 0, cc = 0; s < eLen;) {
      // Copy next three bytes into lower 24 bits of int, paying attension to sign.
      int i = (sArr[s++] & 0xff) << 16 | (sArr[s++] & 0xff) << 8 | (sArr[s++] & 0xff);
      // Encode the int into four chars
      dArr[d++] = (byte) CA[(i >>> 18) & 0x3f];
      dArr[d++] = (byte) CA[(i >>> 12) & 0x3f];
      dArr[d++] = (byte) CA[(i >>> 6) & 0x3f];
      dArr[d++] = (byte) CA[i & 0x3f];
      // Add optional line separator
      if (lineSep && ++cc == 19 && d < dLen - 2) {
        dArr[d++] = "\r";
        dArr[d++] = "\n";
        cc = 0;
      }
    }
    // Pad and encode last bits if source isn"t an even 24 bits.
    int left = sLen - eLen; // 0 - 2.
    if (left > 0) {
      // Prepare the int
      int i = ((sArr[eLen] & 0xff) << 10) | (left == 2 ? ((sArr[sLen - 1] & 0xff) << 2) : 0);
      // Set last four chars
      dArr[dLen - 4] = (byte) CA[i >> 12];
      dArr[dLen - 3] = (byte) CA[(i >>> 6) & 0x3f];
      dArr[dLen - 2] = left == 2 ? (byte) CA[i & 0x3f] : (byte) "=";
      dArr[dLen - 1] = "=";
    }
    return dArr;
  }
  /** Decodes a BASE64 encoded byte array. All illegal characters will be ignored and can handle both arrays with
   * and without line separators.
   * @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
   * @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
   * (including "=") isn"t divideable by 4. (I.e. definitely corrupted).
   */
  public final static byte[] decode(byte[] sArr)
  {
    // Check special case
    int sLen = sArr.length;
    // Count illegal characters (including "\r", "\n") to know what size the returned array will be,
    // so we don"t have to reallocate & copy it later.
    int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that"s a bonus...)
    for (int i = 0; i < sLen; ++i) {
      if (IA[sArr[i] & 0xff] < 0) {
        ++sepCnt;
      }
    }
    // Check so that legal chars (including "=") are evenly divideable by 4 as specified in RFC 2045.
    if ((sLen - sepCnt) % 4 != 0) {
      return null;
    }
    int pad = 0;
    for (int i = sLen; i > 1 && IA[sArr[--i] & 0xff] <= 0;) {
      if (sArr[i] == "=") {
        ++pad;
      }
    }
    int len = ((sLen - sepCnt) * 6 >> 3) - pad;
    byte[] dArr = new byte[len];       // Preallocate byte[] of exact length
    for (int s = 0, d = 0; d < len;) {
      // Assemble three bytes into an int from four "valid" characters.
      int i = 0;
      for (int j = 0; j < 4; ++j) {   // j only increased if a valid char was found.
        int c = IA[sArr[s++] & 0xff];
        if (c >= 0) {
          i |= c << (18 - j * 6);
        } else {
          --j;
        }
      }
      // Add the bytes
      dArr[d++] = (byte) (i >> 16);
      if (d < len) {
        dArr[d++]= (byte) (i >> 8);
        if (d < len) {
          dArr[d++] = (byte) i;
        }
      }
    }
    return dArr;
  }

  /* * Decodes a BASE64 encoded byte array that is known to be resonably well formatted. The method is about twice as
   * fast as {@link #decode(byte[])}. The preconditions are:<br>
   * + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
   * + Line separator must be "\r\n", as specified in RFC 2045
   * + The array must not contain illegal characters within the encoded string<br>
   * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
   * @param sArr The source array. Length 0 will return an empty array. <code>null</code> will throw an exception.
   * @return The decoded array of bytes. May be of length 0.
   * /
  public final static byte[] decodeFast(byte[] sArr)
  {
    // Check special case
    int sLen = sArr.length;
    if (sLen == 0) {
      return new byte[0];
    }
    int sIx = 0, eIx = sLen - 1;    // Start and end index after trimming.
    // Trim illegal chars from start
    while (sIx < eIx && IA[sArr[sIx] & 0xff] < 0) {
      ++sIx;
    }
    // Trim illegal chars from end
    while (eIx > 0 && IA[sArr[eIx] & 0xff] < 0) {
      --eIx;
    }
    // get the padding count (=) (0, 1 or 2)
    int pad = sArr[eIx] == "=" ? (sArr[eIx - 1] == "=" ? 2 : 1) : 0;  // Count "=" at end.
    int cCnt = eIx - sIx + 1;   // Content count including possible separators
    int sepCnt = sLen > 76 ? (sArr[76] == "\r" ? cCnt / 78 : 0) << 1 : 0;
    int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
    byte[] dArr = new byte[len];       // Preallocate byte[] of exact length
    // Decode all but the last 0 - 2 bytes.
    int d = 0;
    for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) {
      // Assemble three bytes into an int from four "valid" characters.
      int i = IA[sArr[sIx++]] << 18 | IA[sArr[sIx++]] << 12 | IA[sArr[sIx++]] << 6 | IA[sArr[sIx++]];
      // Add the bytes
      dArr[d++] = (byte) (i >> 16);
      dArr[d++] = (byte) (i >> 8);
      dArr[d++] = (byte) i;
      // If line separator, jump over it.
      if (sepCnt > 0 && ++cc == 19) {
        sIx += 2;
        cc = 0;
      }
    }
    if (d < len) {
      // Decode last 1-3 bytes (incl "=") into 1-3 bytes
      int i = 0;
      for (int j = 0; sIx <= eIx - pad; ++j) {
        i |= IA[sArr[sIx++]] << (18 - j * 6);
      }
      for (int r = 16; d < len; r -= 8) {
        dArr[d++] = (byte) (i >> r);
      }
    }
    return dArr;
  }*/
  // ****************************************************************************************
  // * String version
  // ****************************************************************************************
  /** Encodes a raw byte array into a BASE64 <code>String</code> representation i accordance with RFC 2045.
   * @param sArr The bytes to convert. If <code>null</code> or length 0 an empty array will be returned.
   * @param lineSep Optional "\r\n" after 76 characters, unless end of file.<br>
   * No line separator will be in breach of RFC 2045 which specifies max 76 per line but will be a
   * little faster.
   * @return A BASE64 encoded array. Never <code>null</code>.
   */
  public final static String encodeToString(byte[] sArr, boolean lineSep)
  {
    // Reuse char[] since we can"t create a String incrementally anyway and StringBuffer/Builder would be slower.
    return new String(encodeToChar(sArr, lineSep));
  }
  /** Decodes a BASE64 encoded <code>String</code>. All illegal characters will be ignored and can handle both strings with
   * and without line separators.<br>
   * <b>Note!</b> It can be up to about 2x the speed to call <code>decode(str.toCharArray())</code> instead. That
   * will create a temporary array though. This version will use <code>str.charAt(i)</code> to iterate the string.
   * @param str The source string. <code>null</code> or length 0 will return an empty array.
   * @return The decoded array of bytes. May be of length 0. Will be <code>null</code> if the legal characters
   * (including "=") isn"t divideable by 4.  (I.e. definitely corrupted).
   */
  public final static byte[] decode(String str)
  {
    // Check special case
    int sLen = str != null ? str.length() : 0;
    if (sLen == 0) {
      return new byte[0];
    }
    //assert str != null;
    // Count illegal characters (including "\r", "\n") to know what size the returned array will be,
    // so we don"t have to reallocate & copy it later.
    int sepCnt = 0; // Number of separator characters. (Actually illegal characters, but that"s a bonus...)
    for (int i = 0; i < sLen; ++i) {
      if (IA[str.charAt(i)] < 0) {
        ++sepCnt;
      }
    }
    // Check so that legal chars (including "=") are evenly divideable by 4 as specified in RFC 2045.
    if ((sLen - sepCnt) % 4 != 0) {
      return null;
    }
    // Count "=" at end
    int pad = 0;
    for (int i = sLen; i > 1 && IA[str.charAt(--i)] <= 0;) {
      if (str.charAt(i) == "=") {
        ++pad;
      }
    }
    int len = ((sLen - sepCnt) * 6 >> 3) - pad;
    byte[] dArr = new byte[len];       // Preallocate byte[] of exact length
    for (int s = 0, d = 0; d < len;) {
      // Assemble three bytes into an int from four "valid" characters.
      int i = 0;
      for (int j = 0; j < 4; ++j) {   // j only increased if a valid char was found.
        int c = IA[str.charAt(s++)];
        if (c >= 0) {
          i |= c << (18 - j * 6);
        } else {
          --j;
        }
      }
      // Add the bytes
      dArr[d++] = (byte) (i >> 16);
      if (d < len) {
        dArr[d++]= (byte) (i >> 8);
        if (d < len) {
          dArr[d++] = (byte) i;
        }
      }
    }
    return dArr;
  }
  /* * Decodes a BASE64 encoded string that is known to be resonably well formatted. The method is about twice as
   * fast as {@link #decode(String)}. The preconditions are:<br>
   * + The array must have a line length of 76 chars OR no line separators at all (one line).<br>
   * + Line separator must be "\r\n", as specified in RFC 2045
   * + The array must not contain illegal characters within the encoded string<br>
   * + The array CAN have illegal characters at the beginning and end, those will be dealt with appropriately.<br>
   * @param s The source string. Length 0 will return an empty array. <code>null</code> will throw an exception.
   * @return The decoded array of bytes. May be of length 0.
   * /
  public final static byte[] decodeFast(String s)
  {
    // Check special case
    int sLen = s.length();
    if (sLen == 0) {
      return new byte[0];
    }
    int sIx = 0, eIx = sLen - 1;    // Start and end index after trimming.
    // Trim illegal chars from start
    while (sIx < eIx && IA[s.charAt(sIx) & 0xff] < 0) {
      ++sIx;
    }
    // Trim illegal chars from end
    while (eIx > 0 && IA[s.charAt(eIx) & 0xff] < 0) {
      --eIx;
    }
    // get the padding count (=) (0, 1 or 2)
    int pad = s.charAt(eIx) == "=" ? (s.charAt(eIx - 1) == "=" ? 2 : 1) : 0;  // Count "=" at end.
    int cCnt = eIx - sIx + 1;   // Content count including possible separators
    int sepCnt = sLen > 76 ? (s.charAt(76) == "\r" ? cCnt / 78 : 0) << 1 : 0;
    int len = ((cCnt - sepCnt) * 6 >> 3) - pad; // The number of decoded bytes
    byte[] dArr = new byte[len];       // Preallocate byte[] of exact length
    // Decode all but the last 0 - 2 bytes.
    int d = 0;
    for (int cc = 0, eLen = (len / 3) * 3; d < eLen;) {
      // Assemble three bytes into an int from four "valid" characters.
      int i = IA[s.charAt(sIx++)] << 18 | IA[s.charAt(sIx++)] << 12 | IA[s.charAt(sIx++)] << 6 | IA[s.charAt(sIx++)];
      // Add the bytes
      dArr[d++] = (byte) (i >> 16);
      dArr[d++] = (byte) (i >> 8);
      dArr[d++] = (byte) i;
      // If line separator, jump over it.
      if (sepCnt > 0 && ++cc == 19) {
        sIx += 2;
        cc = 0;
      }
    }
    if (d < len) {
      // Decode last 1-3 bytes (incl "=") into 1-3 bytes
      int i = 0;
      for (int j = 0; sIx <= eIx - pad; ++j) {
        i |= IA[s.charAt(sIx++)] << (18 - j * 6);
      }
      for (int r = 16; d < len; r -= 8) {
        dArr[d++] = (byte) (i >> r);
      }
    }
    return dArr;
  }*/
}





array of byte to encode

     
/*   Copyright 2004 The Apache Software Foundation
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *  limitations under the License.
 */
//xmlbeans
import java.io.UnsupportedEncodingException;
/**
 * format validation
 *
 * This class encodes/decodes hexadecimal data
 * @author Jeffrey Rodriguez
 * @version $Id: HexBin.java 125124 2005-01-14 00:23:54Z kkrouse $
 */
public class Main {
  static private final int  BASELENGTH   = 255;
  static private final int  LOOKUPLENGTH = 16;
  static private byte [] hexNumberTable    = new byte[BASELENGTH];
  static private byte [] lookUpHexAlphabet = new byte[LOOKUPLENGTH];

  static {
      for (int i = 0; i<BASELENGTH; i++ ) {
          hexNumberTable[i] = -1;
      }
      for ( int i = "9"; i >= "0"; i--) {
          hexNumberTable[i] = (byte) (i-"0");
      }
      for ( int i = "F"; i>= "A"; i--) {
          hexNumberTable[i] = (byte) ( i-"A" + 10 );
      }
      for ( int i = "f"; i>= "a"; i--) {
         hexNumberTable[i] = (byte) ( i-"a" + 10 );
      }
      for(int i = 0; i<10; i++ )
          lookUpHexAlphabet[i] = (byte) ("0"+i );
      for(int i = 10; i<=15; i++ )
          lookUpHexAlphabet[i] = (byte) ("A"+i -10);
  }
  /**
   * array of byte to encode
   *
   * @param binaryData
   * @return return encode binary array
   */
  static public byte[] encode(byte[] binaryData) {
      if (binaryData == null)
          return null;
      int lengthData   = binaryData.length;
      int lengthEncode = lengthData * 2;
      byte[] encodedData = new byte[lengthEncode];
      for( int i = 0; i<lengthData; i++ ){
          encodedData[i*2] = lookUpHexAlphabet[(binaryData[i] >> 4) & 0xf];
          encodedData[i*2+1] = lookUpHexAlphabet[ binaryData[i] & 0xf];
      }
      return encodedData;
  }
}





Base64 Character encoder as specified in RFC1113

    
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* $Id: Base64EncodeStream.java 447277 2006-09-18 06:19:34Z jeremias $ */

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
/**
 * This class implements a Base64 Character encoder as specified in RFC1113.
 * Unlike some other encoding schemes there is nothing in this encoding
 * that indicates where a buffer starts or ends.
 *
 * This means that the encoded text will simply start with the first line
 * of encoded text and end with the last line of encoded text.
 *
 * @author 
 * @author      Chuck McManis
 * @version $Id: Base64EncodeStream.java 447277 2006-09-18 06:19:34Z jeremias $
 */
public class Base64EncodeStream extends OutputStream {
    /** This array maps the 6 bit values to their characters */
    private final static byte pem_array[] = {
    //   0   1   2   3   4   5   6   7
        "A","B","C","D","E","F","G","H", // 0
        "I","J","K","L","M","N","O","P", // 1
        "Q","R","S","T","U","V","W","X", // 2
        "Y","Z","a","b","c","d","e","f", // 3
        "g","h","i","j","k","l","m","n", // 4
        "o","p","q","r","s","t","u","v", // 5
        "w","x","y","z","0","1","2","3", // 6
        "4","5","6","7","8","9","+","/"  // 7
    };
    byte [] atom = new byte[3];
    int     atomLen = 0;
    byte [] encodeBuf = new byte[4];
    int     lineLen = 0;
    PrintStream  out;
    boolean closeOutOnClose;
    public Base64EncodeStream(OutputStream out) {
        this.out = new PrintStream(out);
        closeOutOnClose = true;
    }
    public Base64EncodeStream(OutputStream out, boolean closeOutOnClose) {
        this.out = new PrintStream(out);
        this.closeOutOnClose = closeOutOnClose;
    }
    public void close () throws IOException {
        if (out != null) {
            encodeAtom();
            out.flush();        
            if (closeOutOnClose)
                out.close();
            out=null;
        }
    }
    /**
     * This can"t really flush out output since that may generate
     * "=" chars which would indicate the end of the stream.
     * Instead we flush out.  You can only be sure all output is 
     * writen by closing this stream.
     */
    public void flush() throws IOException {
        out.flush();
    }
    public void write(int b) throws IOException {
        atom[atomLen++] = (byte)b;
        if (atomLen == 3)
            encodeAtom();
    }
    public void write(byte []data) throws IOException {
        encodeFromArray(data, 0, data.length);
    }
    public void write(byte [] data, int off, int len) throws IOException {
        encodeFromArray(data, off, len);
    }
    /**
     * enocodeAtom - Take three bytes of input and encode it as 4
     * printable characters. Note that if the length in len is less
     * than three is encodes either one or two "=" signs to indicate
     * padding characters.
     */
    void encodeAtom() throws IOException {
        byte a, b, c;
        switch (atomLen) {
        case 0: return;
        case 1:
            a = atom[0];
            encodeBuf[0] = pem_array[((a >>> 2) & 0x3F)];
            encodeBuf[1] = pem_array[((a <<  4) & 0x30)];
            encodeBuf[2] = encodeBuf[3] = "=";
            break;
        case 2:
            a = atom[0];
            b = atom[1];
            encodeBuf[0] = pem_array[((a >>> 2) & 0x3F)];
            encodeBuf[1] = pem_array[(((a << 4) & 0x30) | ((b >>> 4) & 0x0F))];
            encodeBuf[2] = pem_array[((b  << 2) & 0x3C)];
            encodeBuf[3] = "=";
            break;
        default:
            a = atom[0];
            b = atom[1];
            c = atom[2];
            encodeBuf[0] = pem_array[((a >>> 2) & 0x3F)];
            encodeBuf[1] = pem_array[(((a << 4) & 0x30) | ((b >>> 4) & 0x0F))];
            encodeBuf[2] = pem_array[(((b << 2) & 0x3C) | ((c >>> 6) & 0x03))];
            encodeBuf[3] = pem_array[c & 0x3F];
        }
        if (lineLen == 64) {
            out.println();
            lineLen = 0;
        }
        out.write(encodeBuf);
        lineLen += 4;
        atomLen = 0;
    }
    /**
     * enocodeAtom - Take three bytes of input and encode it as 4
     * printable characters. Note that if the length in len is less
     * than three is encodes either one or two "=" signs to indicate
     * padding characters.
     */
    void encodeFromArray(byte[] data, int offset, int len) 
        throws IOException{
        byte a, b, c;
        if (len == 0)
            return;
        // System.out.println("atomLen: " + atomLen + 
        //                    " len: " + len + 
        //                    " offset:  " + offset);
        if (atomLen != 0) {
            switch(atomLen) {
            case 1:
                atom[1] = data[offset++]; len--; atomLen++;
                if (len == 0) return;
                atom[2] = data[offset++]; len--; atomLen++;
                break;
            case 2:
                atom[2] = data[offset++]; len--; atomLen++;
                break;
            default:
            }
            encodeAtom();
        }
        while (len >=3) {
            a = data[offset++];
            b = data[offset++];
            c = data[offset++];
            
            encodeBuf[0] = pem_array[((a >>> 2) & 0x3F)];
            encodeBuf[1] = pem_array[(((a << 4) & 0x30) | ((b >>> 4) & 0x0F))];
            encodeBuf[2] = pem_array[(((b << 2) & 0x3C) | ((c >>> 6) & 0x03))];
            encodeBuf[3] = pem_array[c & 0x3F];
            out.write(encodeBuf);
            lineLen += 4;
            if (lineLen == 64) {
                out.println();
                lineLen = 0;
            }
            len -=3;
        }
        switch (len) {
        case 1:
            atom[0] = data[offset];
            break;
        case 2:
            atom[0] = data[offset];
            atom[1] = data[offset+1];
            break;
        default:
        }
        atomLen = len;
    }
    
    
}





Base64 encoder/decoder

    

/***************************************************************
Copyright (c) 1998, 1999 Nate Sammons <nate@protomatter.ru>  
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA  02111-1307, USA.
Contact support@protomatter.ru with your questions, comments,
gripes, praise, etc...
***************************************************************/

/***************************************************************
  - moved to the net.matuschek.util tree by Daniel Matuschek
  - replaced deprecated getBytes() method in method decode
  - added String encode(String) method to encode a String to 
    base64
 ***************************************************************/
/**
 * Base64 encoder/decoder.  Does not stream, so be careful with
 * using large amounts of data
 *
 * @author Nate Sammons
 * @author Daniel Matuschek
 * @version $Id: Base64.java,v 1.4 2001/04/17 10:09:27 matuschd Exp $
 */
public class Base64
{
  private Base64()
  {
    super();
  }
  /**
   *  Encode some data and return a String.
   */
  public final static String encode(byte[] d)
  {
    if (d == null) return null;
    byte data[] = new byte[d.length+2];
    System.arraycopy(d, 0, data, 0, d.length);
    byte dest[] = new byte[(data.length/3)*4];
    // 3-byte to 4-byte conversion
    for (int sidx = 0, didx=0; sidx < d.length; sidx += 3, didx += 4)
    {
      dest[didx]   = (byte) ((data[sidx] >>> 2) & 077);
      dest[didx+1] = (byte) ((data[sidx+1] >>> 4) & 017 |
                  (data[sidx] << 4) & 077);
      dest[didx+2] = (byte) ((data[sidx+2] >>> 6) & 003 |
                  (data[sidx+1] << 2) & 077);
      dest[didx+3] = (byte) (data[sidx+2] & 077);
    }
    // 0-63 to ascii printable conversion
    for (int idx = 0; idx <dest.length; idx++)
    {
      if (dest[idx] < 26)     dest[idx] = (byte)(dest[idx] + "A");
      else if (dest[idx] < 52)  dest[idx] = (byte)(dest[idx] + "a" - 26);
      else if (dest[idx] < 62)  dest[idx] = (byte)(dest[idx] + "0" - 52);
      else if (dest[idx] < 63)  dest[idx] = (byte)"+";
      else            dest[idx] = (byte)"/";
    }
    // add padding
    for (int idx = dest.length-1; idx > (d.length*4)/3; idx--)
    {
      dest[idx] = (byte)"=";
    }
    return new String(dest);
  }
  /**
   * Encode a String using Base64 using the default platform encoding
   **/
  public final static String encode(String s) {
    return encode(s.getBytes());
  }
  /**
   *  Decode data and return bytes.
   */
  public final static byte[] decode(String str)
  {
    if (str == null)  return  null;
    byte data[] = str.getBytes();
    return decode(data);
  }
  /**
   *  Decode data and return bytes.  Assumes that the data passed
   *  in is ASCII text.
   */
  public final static byte[] decode(byte[] data)
  {
    int tail = data.length;
    while (data[tail-1] == "=")  tail--;
    byte dest[] = new byte[tail - data.length/4];
    // ascii printable to 0-63 conversion
    for (int idx = 0; idx <data.length; idx++)
    {
      if (data[idx] == "=")    data[idx] = 0;
      else if (data[idx] == "/") data[idx] = 63;
      else if (data[idx] == "+") data[idx] = 62;
      else if (data[idx] >= "0"  &&  data[idx] <= "9")
        data[idx] = (byte)(data[idx] - ("0" - 52));
      else if (data[idx] >= "a"  &&  data[idx] <= "z")
        data[idx] = (byte)(data[idx] - ("a" - 26));
      else if (data[idx] >= "A"  &&  data[idx] <= "Z")
        data[idx] = (byte)(data[idx] - "A");
    }
    // 4-byte to 3-byte conversion
    int sidx, didx;
    for (sidx = 0, didx=0; didx < dest.length-2; sidx += 4, didx += 3)
    {
      dest[didx]   = (byte) ( ((data[sidx] << 2) & 255) |
              ((data[sidx+1] >>> 4) & 3) );
      dest[didx+1] = (byte) ( ((data[sidx+1] << 4) & 255) |
              ((data[sidx+2] >>> 2) & 017) );
      dest[didx+2] = (byte) ( ((data[sidx+2] << 6) & 255) |
              (data[sidx+3] & 077) );
    }
    if (didx < dest.length)
    {
      dest[didx]   = (byte) ( ((data[sidx] << 2) & 255) |
              ((data[sidx+1] >>> 4) & 3) );
    }
    if (++didx < dest.length)
    {
      dest[didx]   = (byte) ( ((data[sidx+1] << 4) & 255) |
              ((data[sidx+2] >>> 2) & 017) );
    }
    return dest;
  }
  /**
   *  A simple test that encodes and decodes the first commandline argument.
   */
  public static final void main(String[] args)
  {
    if (args.length != 1)
    {
      System.out.println("Usage: Base64 string");
      System.exit(0);
    }
    try
    {
      String e = Base64.encode(args[0].getBytes());
      String d = new String(Base64.decode(e));
      System.out.println("Input   = "" + args[0] + """);
      System.out.println("Encoded = "" + e + """);
      System.out.println("Decoded = "" + d + """);
    }
    catch (Exception x)
    {
      x.printStackTrace();
    }
  }
}





BASE64 encoder implementation

    
/*
 * Copyright � World Wide Web Consortium, (Massachusetts Institute of Technology, 
 * Institut National de Recherche en Informatique et en Automatique, Keio University).
 * All Rights Reserved. http://www.w3.org/Consortium/Legal/
 */
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
/**
 * BASE64 encoder implementation.
 * This object takes as parameter an input stream and an output stream. It
 * encodes the input stream, using the BASE64 encoding rules, as defined
 * in 
 * and emit the resulting data to the output stream.
 * @see org.w3c.tools.codec.Base64Decoder
 */
public class Base64Encoder
{
  private static final int BUFFER_SIZE = 1024;
  private static byte encoding[] =
    {
      (byte) "A", (byte) "B", (byte) "C", (byte) "D", (byte) "E", (byte) "F", (byte) "G", (byte) "H", // 0-7
      (byte) "I", (byte) "J", (byte) "K", (byte) "L", (byte) "M", (byte) "N", (byte) "O", (byte) "P", // 8-15
      (byte) "Q", (byte) "R", (byte) "S", (byte) "T", (byte) "U", (byte) "V", (byte) "W", (byte) "X", // 16-23
      (byte) "Y", (byte) "Z", (byte) "a", (byte) "b", (byte) "c", (byte) "d", (byte) "e", (byte) "f", // 24-31
      (byte) "g", (byte) "h", (byte) "i", (byte) "j", (byte) "k", (byte) "l", (byte) "m", (byte) "n", // 32-39
      (byte) "o", (byte) "p", (byte) "q", (byte) "r", (byte) "s", (byte) "t", (byte) "u", (byte) "v", // 40-47
      (byte) "w", (byte) "x", (byte) "y", (byte) "z", (byte) "0", (byte) "1", (byte) "2", (byte) "3", // 48-55
      (byte) "4", (byte) "5", (byte) "6", (byte) "7", (byte) "8", (byte) "9", (byte) "+", (byte) "/", // 56-63
      (byte) "=" // 64
  };
  InputStream in = null;
  OutputStream out = null;
  boolean stringp = false;
  private final int get1(byte buf[], int off)
  {
    return (buf[off] & 0xfc) >> 2;
  }
  private final int get2(byte buf[], int off)
  {
    return ((buf[off] & 0x3) << 4) | ((buf[off + 1] & 0xf0) >>> 4);
  }
  private final int get3(byte buf[], int off)
  {
    return ((buf[off + 1] & 0x0f) << 2) | ((buf[off + 2] & 0xc0) >>> 6);
  }
  private static final int get4(byte buf[], int off)
  {
    return buf[off + 2] & 0x3f;
  }
  /**
   * Process the data: encode the input stream to the output stream.
   * This method runs through the input stream, encoding it to the output 
   * stream.
   * @exception IOException If we weren"t able to access the input stream or
   *    the output stream.
   */
  public void process() throws IOException
  {
    byte buffer[] = new byte[BUFFER_SIZE];
    int got = -1;
    int off = 0;
    int count = 0;
    while ((got = in.read(buffer, off, BUFFER_SIZE - off)) > 0)
    {
      if (got >= 3)
      {
        got += off;
        off = 0;
        while (off + 3 <= got)
        {
          int c1 = get1(buffer, off);
          int c2 = get2(buffer, off);
          int c3 = get3(buffer, off);
          int c4 = get4(buffer, off);
          switch (count)
          {
            case 73 :
              out.write(encoding[c1]);
              out.write(encoding[c2]);
              out.write(encoding[c3]);
              out.write("\n");
              out.write(encoding[c4]);
              count = 1;
              break;
            case 74 :
              out.write(encoding[c1]);
              out.write(encoding[c2]);
              out.write("\n");
              out.write(encoding[c3]);
              out.write(encoding[c4]);
              count = 2;
              break;
            case 75 :
              out.write(encoding[c1]);
              out.write("\n");
              out.write(encoding[c2]);
              out.write(encoding[c3]);
              out.write(encoding[c4]);
              count = 3;
              break;
            case 76 :
              out.write("\n");
              out.write(encoding[c1]);
              out.write(encoding[c2]);
              out.write(encoding[c3]);
              out.write(encoding[c4]);
              count = 4;
              break;
            default :
              out.write(encoding[c1]);
              out.write(encoding[c2]);
              out.write(encoding[c3]);
              out.write(encoding[c4]);
              count += 4;
              break;
          }
          off += 3;
        }
        // Copy remaining bytes to beginning of buffer:
        for (int i = 0; i < 3; i++)
          buffer[i] = (i < got - off) ? buffer[off + i] : ((byte) 0);
        off = got - off;
      }
      else
      {
        // Total read amount is less then 3 bytes:
        off += got;
      }
    }
    // Manage the last bytes, from 0 to off:
    switch (off)
    {
      case 1 :
        out.write(encoding[get1(buffer, 0)]);
        out.write(encoding[get2(buffer, 0)]);
        out.write("=");
        out.write("=");
        break;
      case 2 :
        out.write(encoding[get1(buffer, 0)]);
        out.write(encoding[get2(buffer, 0)]);
        out.write(encoding[get3(buffer, 0)]);
        out.write("=");
    }
    return;
  }
  /**
   * Encode the content of this encoder, as a string.
   * This methods encode the String content, that was provided at creation 
   * time, following the BASE64 rules, as specified in the rfc1521.
   * @return A String, reprenting the encoded content of the input String.
   */
  public String processString()
  {
    if (!stringp)
      throw new RuntimeException(
        this.getClass().getName()
          + "[processString]"
          + "invalid call (not a String)");
    try
    {
      process();
    }
    catch (IOException e)
    {
    }
    return ((ByteArrayOutputStream) out).toString();
  }
  /**
   * Create a new Base64 encoder, to encode the given string.
   * @param input The String to be encoded.
   */
  public Base64Encoder(String input)
  {
    byte bytes[];
    try
    {
      bytes = input.getBytes("ISO-8859-1");
    }
    catch (UnsupportedEncodingException ex)
    {
      throw new RuntimeException(
        this.getClass().getName()
          + "[Constructor] Unable to convert"
          + "properly char to bytes");
    }
    this.stringp = true;
    this.in = new ByteArrayInputStream(bytes);
    this.out = new ByteArrayOutputStream();
  }
  /**
   * Create a new Base64 encoder, encoding input to output.
   * @param in The input stream to be encoded.
   * @param out The output stream, to write encoded data to.
   */
  public Base64Encoder(InputStream in, OutputStream out)
  {
    this.in = in;
    this.out = out;
    this.stringp = false;
  }
  /**
   * Testing the encoder.
   * Run with one argument, prints the encoded version of it.
   */
  public static void main(String args[])
  {
    if (args.length != 1)
    {
      System.out.println("Base64Encoder <string>");
      System.exit(0);
    }
    Base64Encoder b = new Base64Encoder(args[0]);
    System.out.println("[" + b.processString() + "]");
    // joe:eoj -> am9lOmVvag==
    // 12345678:87654321 -> MTIzNDU2Nzg6ODc2NTQzMjE=
  }
}





Base-64 Encoder - translates from base-64 text into binary

    
/*
 * Base64Encoder.java
 *
 * Created on 20 December 2005, 11:15
 *
 */

import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CoderResult;
/**
 * <p>Base-64 Encoder - translates from base-64 text into binary.</p>
 * <p>Whitespace is ignored, so is anything following a terminating = 
 * character.</p>
 * @author Malcolm McMahon
 * @version $Revision: 1.1 $
 */
public class Base64Encoder extends CharsetEncoder {
    final static int CHARCODE_INVALID = -1;
    final static int CHARCODE_PADDER = -2;
    final static int CHARCODE_WHITESPACE = -3;
    
    int[] encTable;
    int encState;
    Byte excessByte;
    int bits;
    /** Creates a new instance of Base64Encoder
     * @param cs The Charset which created this
     * @param encTable Table which maps chacacters onto 6 bit values.
     */
    public Base64Encoder(Charset cs, int[] encTable) {
        super(cs, 1.4f, 2f);
        this.encTable = encTable;
    }
    
    private boolean out(ByteBuffer bb, int outValue) {
        if(bb.remaining() > 0) {
            bb.put((byte)outValue);
            return true;
        } else {
            excessByte = Byte.valueOf((byte)outValue);
            return false;
        }
    }
    
    
    
    
    /**
     * Flushes this encoder.
     *
     * <p> The default implementation of this method does nothing, and always
     * returns {@link CoderResult#UNDERFLOW}.  This method should be overridden
     * by encoders that may need to write final bytes to the output buffer
     * once the entire input sequence has been read. </p>
     *
     * @param  out
     *         The output byte buffer
     *
     * @return  A coder-result object, either {@link CoderResult#UNDERFLOW} or
     *          {@link CoderResult#OVERFLOW}
     */
    protected java.nio.charset.CoderResult implFlush(java.nio.ByteBuffer out) {
        if(encState != 0 && encState != 4)
            throw new IllegalArgumentException("Base-64 text ends prematurely");
        if(excessByte == null) {
            implReset();
            return CoderResult.UNDERFLOW;
        }
        if(out.remaining() > 0) {
            out.put(excessByte.byteValue());
            implReset();
            return CoderResult.UNDERFLOW;
        } else
            return CoderResult.OVERFLOW;
        
    }
    
    /**
     * Encodes one or more characters into one or more bytes.
     *
     * <p> This method encapsulates the basic encoding loop, encoding as many
     * characters as possible until it either runs out of input, runs out of room
     * in the output buffer, or encounters an encoding error.  This method is
     * invoked by the {@link #encode encode} method, which handles result
     * interpretation and error recovery.
     *
     * <p> The buffers are read from, and written to, starting at their current
     * positions.  At most {@link Buffer#remaining in.remaining()} characters
     * will be read, and at most {@link Buffer#remaining out.remaining()}
     * bytes will be written.  The buffers" positions will be advanced to
     * reflect the characters read and the bytes written, but their marks and
     * limits will not be modified.
     *
     * <p> This method returns a {@link CoderResult} object to describe its
     * reason for termination, in the same manner as the {@link #encode encode}
     * method.  Most implementations of this method will handle encoding errors
     * by returning an appropriate result object for interpretation by the
     * {@link #encode encode} method.  An optimized implementation may instead
     * examine the relevant error action and implement that action itself.
     *
     * <p> An implementation of this method may perform arbitrary lookahead by
     * returning {@link CoderResult#UNDERFLOW} until it receives sufficient
     * input.  </p>
     *
     * @param  in
     *         The input character buffer
     *
     * @param  out
     *         The output byte buffer
     *
     * @return  A coder-result object describing the reason for termination
     */
    public java.nio.charset.CoderResult encodeLoop(java.nio.CharBuffer in, java.nio.ByteBuffer out) {
        if(excessByte != null) {
            if(out.remaining() > 0) {
                out.put(excessByte.byteValue());
                excessByte = null;
            } else
                return CoderResult.OVERFLOW;
            
        }
        while(in.remaining() > 0) {
            char inch = in.get();
            int code = (int)inch >= encTable.length ? CHARCODE_INVALID : encTable[(int)inch];
            if(encState < 4) {
                switch(code) {
                    case CHARCODE_INVALID:
                        throw new IllegalArgumentException("Invalid base-64 character"" + inch + """ );
                    case CHARCODE_WHITESPACE:
                        break;
                    case CHARCODE_PADDER:
                        if(encState == 1)
                            throw new IllegalArgumentException("Mal-formed base-64 (= after one character");
                        encState = 4;
                        break;
                    default:
                        switch(encState) {
                            case 0:
                                bits = code << 2;
                                encState = 1;
                                break;
                            case 1:
                                encState = 2;
                                int v = bits | ((code >> 4) & 3);
                                bits = (code << 4) & 0xF0;
                                if(!out(out, v))
                                    return CoderResult.OVERFLOW;
                                break;
                            case 2:
                                encState = 3;
                                v = bits | (code >> 2) & 0x0f;
                                bits = (code << 6) & 0xC0;
                                if(!out(out, v))
                                    return CoderResult.OVERFLOW;
                                break;
                            case 3:
                                encState = 0;
                                bits |= (code & 0x3f);
                                if(!out(out, bits))
                                    return CoderResult.OVERFLOW;
                                break;
                        }
                        
                        break;
                }
                
                
            }
        }
        return CoderResult.UNDERFLOW;
    }
    /**
     * Reset - clear encoder state
     */
    protected void implReset() {
        encState = 0;
        bits = 0;
        excessByte = null;
    }
    
}





Base64 encoding/decoding.

    
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common
 * Development and Distribution License("CDDL") (collectively, the
 * "License"). You may not use this file except in compliance with the
 * License. You can obtain a copy of the License at
 * http://www.netbeans.org/cddl-gplv2.html
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 * specific language governing permissions and limitations under the
 * License.  When distributing the software, include this License Header
 * Notice in each file and include the License file at
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Sun in the GPL Version 2 section of the License file that
 * accompanied this code. If applicable, add the following below the
 * License Header, with the fields enclosed by brackets [] replaced by
 * your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * Contributor(s):
 *
 * The Original Software is NetBeans. The Initial Developer of the Original
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 * Microsystems, Inc. All Rights Reserved.
 *
 * If you wish your version of this file to be governed by only the CDDL
 * or only the GPL Version 2, indicate your decision by adding
 * "[Contributor] elects to include this software in this distribution
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 * single choice of license, a recipient has the option to distribute
 * your version of this file under either the CDDL, the GPL Version 2 or
 * to extend the choice of license to its licensees as provided above.
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 * Version 2 license, then the option applies only if the new code is
 * made subject to such option by the copyright holder.
 */
/** This class provides Base64 encoding/decoding.
 */
public class Base64
{
    private Base64()
    {
        //Avoid instantiation of this class
    }
    
    /** Encodes datas using base64 encoding.
     * @param abyte0 data for encoding
     * @return encoded string
     */
    static String encode(final byte abyte0[])
    {
        final StringBuffer stringbuffer = new StringBuffer();
        for(int i = 0; i < abyte0.length; i += 3)
            stringbuffer.append(encodeBlock(abyte0, i));
        
        return stringbuffer.toString();
    }
    
    private static char[] encodeBlock(final byte abyte0[], final int i)
    {
        int j = 0;
        final int k = abyte0.length - i - 1;
        final int l = k < 2 ? k : 2;
        for(int i1 = 0; i1 <= l; i1++)
        {
            final byte byte0 = abyte0[i + i1];
            final int j1 = byte0 >= 0 ? ((int) (byte0)) : byte0 + 256;
            j += j1 << 8 * (2 - i1);
        }
        
        char ac[] = new char[4];
        for(int k1 = 0; k1 < 4; k1++)
        {
            final int l1 = j >>> 6 * (3 - k1) & 0x3f;
            ac[k1] = getChar(l1);
        }
        
        if(k < 1)
            ac[2] = "=";
        if(k < 2)
            ac[3] = "=";
        return ac;
    }
    
    private static char getChar(final int i)
    {
        if(i >= 0 && i <= 25)
            return (char)(65 + i);
        if(i >= 26 && i <= 51)
            return (char)(97 + (i - 26));
        if(i >= 52 && i <= 61)
            return (char)(48 + (i - 52));
        if(i == 62)
            return "+";
        return i != 63 ? "?" : "/";
    }
    
    /** Decode string using Base64 encoding.
     * @param s string for decoding
     * @return decoded data
     */
    static byte[] decode(final String s)
    {
        if (s.length() == 0) return new byte[0];
        int i = 0;
        for(int j = s.length() - 1; j > 0 && s.charAt(j) == "="; j--)
            i++;
        
        final int k = (s.length() * 6) / 8 - i;
        byte abyte0[] = new byte[k];
        int l = 0;
        for(int i1 = 0; i1 < s.length(); i1 += 4)
        {
            final int j1 = (getValue(s.charAt(i1)) << 18) + (getValue(s.charAt(i1 + 1)) << 12) + (getValue(s.charAt(i1 + 2)) << 6) + getValue(s.charAt(i1 + 3));
            for(int k1 = 0; k1 < 3 && l + k1 < abyte0.length; k1++)
                abyte0[l + k1] = (byte)(j1 >> 8 * (2 - k1) & 0xff);
            
            l += 3;
        }
        return abyte0;
    }
    
    private static int getValue(final char c)
    {
        if(c >= "A" && c <= "Z")
            return c - 65;
        if(c >= "a" && c <= "z")
            return (c - 97) + 26;
        if(c >= "0" && c <= "9")
            return (c - 48) + 52;
        if(c == "+")
            return 62;
        if(c == "/")
            return 63;
        return c != "=" ? -1 : 0;
    }
}





Base64 from by Funambol, Inc.

    
/*
 * Funambol is a mobile platform developed by Funambol, Inc. 
 * Copyright (C) 2003 - 2007 Funambol, Inc.
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by
 * the Free Software Foundation with the addition of the following permission 
 * added to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED
 * WORK IN WHICH THE COPYRIGHT IS OWNED BY FUNAMBOL, FUNAMBOL DISCLAIMS THE 
 * WARRANTY OF NON INFRINGEMENT  OF THIRD PARTY RIGHTS.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Affero General Public License 
 * along with this program; if not, see http://www.gnu.org/licenses or write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301 USA.
 * 
 * You can contact Funambol, Inc. headquarters at 643 Bair Island Road, Suite 
 * 305, Redwood City, CA 94063, USA, or at email address info@funambol.ru.
 * 
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 * 
 * In accordance with Section 7(b) of the GNU Affero General Public License
 * version 3, these Appropriate Legal Notices must retain the display of the
 * "Powered by Funambol" logo. If the display of the logo is not reasonably 
 * feasible for technical reasons, the Appropriate Legal Notices must display
 * the words "Powered by Funambol". 
 */

import java.io.UnsupportedEncodingException;
public class Base64 {
    private static final byte[] encodingTable =
        { (byte)"A", (byte)"B", (byte)"C", (byte)"D", (byte)"E", (byte)"F",
                (byte)"G", (byte)"H", (byte)"I", (byte)"J", (byte)"K",
                (byte)"L", (byte)"M", (byte)"N", (byte)"O", (byte)"P",
                (byte)"Q", (byte)"R", (byte)"S", (byte)"T", (byte)"U",
                (byte)"V", (byte)"W", (byte)"X", (byte)"Y", (byte)"Z",
                (byte)"a", (byte)"b", (byte)"c", (byte)"d", (byte)"e",
                (byte)"f", (byte)"g", (byte)"h", (byte)"i", (byte)"j",
                (byte)"k", (byte)"l", (byte)"m", (byte)"n", (byte)"o",
                (byte)"p", (byte)"q", (byte)"r", (byte)"s", (byte)"t",
                (byte)"u", (byte)"v", (byte)"w", (byte)"x", (byte)"y",
                (byte)"z", (byte)"0", (byte)"1", (byte)"2", (byte)"3",
                (byte)"4", (byte)"5", (byte)"6", (byte)"7", (byte)"8",
                (byte)"9", (byte)"+", (byte)"/" };

    /**
     * encode the input data producong a base 64 encoded byte array.
     * 
     * @return a byte array containing the base 64 encoded data.
     */
    public static byte[] encode(byte[] data) {
        byte[] bytes;
        int modulus = data.length % 3;
        if (modulus == 0) {
            bytes = new byte[4 * data.length / 3];
        } else {
            bytes = new byte[4 * ((data.length / 3) + 1)];
        }
        int dataLength = (data.length - modulus);
        int a1, a2, a3;
        for (int i = 0, j = 0; i < dataLength; i += 3, j += 4) {
            a1 = data[i] & 0xff;
            a2 = data[i + 1] & 0xff;
            a3 = data[i + 2] & 0xff;
            bytes[j] = encodingTable[(a1 >>> 2) & 0x3f];
            bytes[j + 1] = encodingTable[((a1 << 4) | (a2 >>> 4)) & 0x3f];
            bytes[j + 2] = encodingTable[((a2 << 2) | (a3 >>> 6)) & 0x3f];
            bytes[j + 3] = encodingTable[a3 & 0x3f];
        }
        /*
         * process the tail end.
         */
        int b1, b2, b3;
        int d1, d2;
        switch (modulus) {
            case 0: /* nothing left to do */
                break;
            case 1:
                d1 = data[data.length - 1] & 0xff;
                b1 = (d1 >>> 2) & 0x3f;
                b2 = (d1 << 4) & 0x3f;
                bytes[bytes.length - 4] = encodingTable[b1];
                bytes[bytes.length - 3] = encodingTable[b2];
                bytes[bytes.length - 2] = (byte)"=";
                bytes[bytes.length - 1] = (byte)"=";
                break;
            case 2:
                d1 = data[data.length - 2] & 0xff;
                d2 = data[data.length - 1] & 0xff;
                b1 = (d1 >>> 2) & 0x3f;
                b2 = ((d1 << 4) | (d2 >>> 4)) & 0x3f;
                b3 = (d2 << 2) & 0x3f;
                bytes[bytes.length - 4] = encodingTable[b1];
                bytes[bytes.length - 3] = encodingTable[b2];
                bytes[bytes.length - 2] = encodingTable[b3];
                bytes[bytes.length - 1] = (byte)"=";
                break;
        }
        return bytes;
    }
    /*
     * set up the decoding table.
     */
    private static final byte[] decodingTable;
    static {
        decodingTable = new byte[128];
        for (int i = 0; i < 128; i++) {
            decodingTable[i] = (byte)-1;
        }
        for (int i = "A"; i <= "Z"; i++) {
            decodingTable[i] = (byte)(i - "A");
        }
        for (int i = "a"; i <= "z"; i++) {
            decodingTable[i] = (byte)(i - "a" + 26);
        }
        for (int i = "0"; i <= "9"; i++) {
            decodingTable[i] = (byte)(i - "0" + 52);
        }
        decodingTable["+"] = 62;
        decodingTable["/"] = 63;
    }

    /**
     * decode the base 64 encoded input data.
     * 
     * @return a byte array representing the decoded data.
     */
    public static byte[] decode(byte[] data) {
        byte[] bytes;
        byte b1, b2, b3, b4;
        data = discardNonBase64Bytes(data);
        if (data[data.length - 2] == "=") {
            bytes = new byte[(((data.length / 4) - 1) * 3) + 1];
        } else if (data[data.length - 1] == "=") {
            bytes = new byte[(((data.length / 4) - 1) * 3) + 2];
        } else {
            bytes = new byte[((data.length / 4) * 3)];
        }
        for (int i = 0, j = 0; i < data.length - 4; i += 4, j += 3) {
            b1 = decodingTable[data[i]];
            b2 = decodingTable[data[i + 1]];
            b3 = decodingTable[data[i + 2]];
            b4 = decodingTable[data[i + 3]];
            bytes[j] = (byte)((b1 << 2) | (b2 >> 4));
            bytes[j + 1] = (byte)((b2 << 4) | (b3 >> 2));
            bytes[j + 2] = (byte)((b3 << 6) | b4);
        }
        if (data[data.length - 2] == "=") {
            b1 = decodingTable[data[data.length - 4]];
            b2 = decodingTable[data[data.length - 3]];
            bytes[bytes.length - 1] = (byte)((b1 << 2) | (b2 >> 4));
        } else if (data[data.length - 1] == "=") {
            b1 = decodingTable[data[data.length - 4]];
            b2 = decodingTable[data[data.length - 3]];
            b3 = decodingTable[data[data.length - 2]];
            bytes[bytes.length - 2] = (byte)((b1 << 2) | (b2 >> 4));
            bytes[bytes.length - 1] = (byte)((b2 << 4) | (b3 >> 2));
        } else {
            b1 = decodingTable[data[data.length - 4]];
            b2 = decodingTable[data[data.length - 3]];
            b3 = decodingTable[data[data.length - 2]];
            b4 = decodingTable[data[data.length - 1]];
            bytes[bytes.length - 3] = (byte)((b1 << 2) | (b2 >> 4));
            bytes[bytes.length - 2] = (byte)((b2 << 4) | (b3 >> 2));
            bytes[bytes.length - 1] = (byte)((b3 << 6) | b4);
        }
        return bytes;
    }

    /**
     * decode the base 64 encoded String data.
     * 
     * TODO: Use the byte version to avoid duplication?
     * 
     * @return a byte array representing the decoded data.
     */
    public static byte[] decode(String data) {
        byte[] bytes;
        byte b1, b2, b3, b4;
        data = discardNonBase64Chars(data);
        if (data.charAt(data.length() - 2) == "=") {
            bytes = new byte[(((data.length() / 4) - 1) * 3) + 1];
        } else if (data.charAt(data.length() - 1) == "=") {
            bytes = new byte[(((data.length() / 4) - 1) * 3) + 2];
        } else {
            bytes = new byte[((data.length() / 4) * 3)];
        }
        for (int i = 0, j = 0; i < data.length() - 4; i += 4, j += 3) {
            b1 = decodingTable[data.charAt(i)];
            b2 = decodingTable[data.charAt(i + 1)];
            b3 = decodingTable[data.charAt(i + 2)];
            b4 = decodingTable[data.charAt(i + 3)];
            bytes[j] = (byte)((b1 << 2) | (b2 >> 4));
            bytes[j + 1] = (byte)((b2 << 4) | (b3 >> 2));
            bytes[j + 2] = (byte)((b3 << 6) | b4);
        }
        if (data.charAt(data.length() - 2) == "=") {
            b1 = decodingTable[data.charAt(data.length() - 4)];
            b2 = decodingTable[data.charAt(data.length() - 3)];
            bytes[bytes.length - 1] = (byte)((b1 << 2) | (b2 >> 4));
        } else if (data.charAt(data.length() - 1) == "=") {
            b1 = decodingTable[data.charAt(data.length() - 4)];
            b2 = decodingTable[data.charAt(data.length() - 3)];
            b3 = decodingTable[data.charAt(data.length() - 2)];
            bytes[bytes.length - 2] = (byte)((b1 << 2) | (b2 >> 4));
            bytes[bytes.length - 1] = (byte)((b2 << 4) | (b3 >> 2));
        } else {
            b1 = decodingTable[data.charAt(data.length() - 4)];
            b2 = decodingTable[data.charAt(data.length() - 3)];
            b3 = decodingTable[data.charAt(data.length() - 2)];
            b4 = decodingTable[data.charAt(data.length() - 1)];
            bytes[bytes.length - 3] = (byte)((b1 << 2) | (b2 >> 4));
            bytes[bytes.length - 2] = (byte)((b2 << 4) | (b3 >> 2));
            bytes[bytes.length - 1] = (byte)((b3 << 6) | b4);
        }
        return bytes;
    }
 
    /**
     * Decode the string and convert back the decoded value into a string
     * using the specified charset. 
     * Use default encoding if charset is null or invalid.
     */
    public static String decode(String data, String charset) {
        if (charset == null){
            // use default
            return new String(Base64.decode(data));            
        }
        try {
            return new String(Base64.decode(data), charset);
        } catch (UnsupportedEncodingException ex) {
            return new String(Base64.decode(data));
        }
    }
    /**
     * Decode the string and convert back the decoded value into a string
     * using the specified charset. 
     * Use default encoding if charset is null or invalid.
     */
    public static String decode(byte[] data, String charset) {
        if (charset == null){
            // use default
            return new String(Base64.decode(data));            
        }
        try {
            return new String(Base64.decode(data), charset);
        } catch (UnsupportedEncodingException ex) {
            return new String(Base64.decode(data));
        }
    }
    // --------------------------------------------------------- Private Methods
    /**
     * Discards any characters outside of the base64 alphabet (see page 25 of
     * RFC 2045) "Any characters outside of the base64 alphabet are to be
     * ignored in base64 encoded data."
     * 
     * @param data
     *            the base64 encoded data
     * @return the data, less non-base64 characters.
     */
    private static byte[] discardNonBase64Bytes(byte[] data) {
        byte temp[] = new byte[data.length];
        int bytesCopied = 0;
        for (int i = 0; i < data.length; i++) {
            if (isValidBase64Byte(data[i])) {
                temp[bytesCopied++] = data[i];
            }
        }
        byte newData[] = new byte[bytesCopied];
        System.arraycopy(temp, 0, newData, 0, bytesCopied);
        return newData;
    }

    /**
     * Discards any characters outside of the base64 alphabet (see page 25 of
     * RFC 2045) "Any characters outside of the base64 alphabet are to be
     * ignored in base64 encoded data."
     * 
     * @param data
     *            the base64 encoded data
     * @return the data, less non-base64 characters.
     */
    private static String discardNonBase64Chars(String data) {
        StringBuffer sb = new StringBuffer();
        int length = data.length();
        for (int i = 0; i < length; i++) {
            if (isValidBase64Byte((byte)(data.charAt(i)))) {
                sb.append(data.charAt(i));
            }
        }
        return sb.toString();
    }

    /**
     * Checks is the given byte is in base64 alphabet
     * 
     * @param b
     *            the byte to check
     * @return boolean true if the byte is in base64 alphabet
     */
    private static boolean isValidBase64Byte(byte b) {
        if (b == "=") {
            return true;
        } else if (b < 0 || b >= 128) {
            return false;
        } else if (decodingTable[b] == -1) {
            return false;
        }
        return true;
    }
}





Base64 Utils

    
// Revised act soap util;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.io.ByteArrayOutputStream;
public class Base64Utils {
  
    private static final char[] S_BASE64CHAR = {
      "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
      "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
      "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d",
      "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
      "o", "p", "q", "r", "s", "t", "u", "v", "w", "x",
      "y", "z", "0", "1", "2", "3", "4", "5", "6", "7",
      "8", "9", "+", "/"
  };
  private static final char S_BASE64PAD = "=";
    private static final byte[] S_DECODETABLE = new byte[128];
  static {
    for (int i = 0; i < S_DECODETABLE.length; i++) {
      S_DECODETABLE[i] = Byte.MAX_VALUE;     }
    for (int i = 0; i < S_BASE64CHAR.length; i++) {       S_DECODETABLE[S_BASE64CHAR[i]] = (byte) i;
    }
  }
  
  private static int base64Decode0(char[] ibuf, byte[] obuf, int wp) {
    int outlen = 3;
    if (ibuf[3] == S_BASE64PAD) {
      outlen = 2;
    }
    if (ibuf[2] == S_BASE64PAD) {
      outlen = 1;
    }
    int b0 = S_DECODETABLE[ibuf[0]];
    int b1 = S_DECODETABLE[ibuf[1]];
    int b2 = S_DECODETABLE[ibuf[2]];
    int b3 = S_DECODETABLE[ibuf[3]];
    switch (outlen) {
      case 1:
        obuf[wp] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3);
        return 1;
      case 2:
        obuf[wp++] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3);
        obuf[wp] = (byte) (b1 << 4 & 0xf0 | b2 >> 2 & 0xf);
        return 2;
      case 3:
        obuf[wp++] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3);
        obuf[wp++] = (byte) (b1 << 4 & 0xf0 | b2 >> 2 & 0xf);
        obuf[wp] = (byte) (b2 << 6 & 0xc0 | b3 & 0x3f);
        return 3;
      default:
        throw new RuntimeException("Internal Errror");
    }
  }
  
  public static byte[] base64Decode(char[] data, int off, int len) {
    char[] ibuf = new char[4];
    int ibufcount = 0;
    byte[] obuf = new byte[len / 4 * 3 + 3];
    int obufcount = 0;
    for (int i = off; i < off + len; i++) {
      char ch = data[i];
      if (ch == S_BASE64PAD
          || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
        ibuf[ibufcount++] = ch;
        if (ibufcount == ibuf.length) {
          ibufcount = 0;
          obufcount += base64Decode0(ibuf, obuf, obufcount);
        }
      }
    }
    if (obufcount == obuf.length) {
      return obuf;
    }
    byte[] ret = new byte[obufcount];
    System.arraycopy(obuf, 0, ret, 0, obufcount);
    return ret;
  }
  
  public static byte[] base64Decode(String data) {
    char[] ibuf = new char[4];
    int ibufcount = 0;
    byte[] obuf = new byte[data.length() / 4 * 3 + 3];
    int obufcount = 0;
    for (int i = 0; i < data.length(); i++) {
      char ch = data.charAt(i);
      if (ch == S_BASE64PAD
          || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
        ibuf[ibufcount++] = ch;
        if (ibufcount == ibuf.length) {
          ibufcount = 0;
          obufcount += base64Decode0(ibuf, obuf, obufcount);
        }
      }
    }
    if (obufcount == obuf.length) {
      return obuf;
    }
    byte[] ret = new byte[obufcount];
    System.arraycopy(obuf, 0, ret, 0, obufcount);
    return ret;
  }
  
  public static byte[] base64Decode(byte[] data) {
    return base64Decode(data, 0, data.length);
  }
  
  public static byte[] base64Decode(byte[] data, int off, int len) {
    char[] ibuf = new char[4];
    int ibufcount = 0;
    byte[] obuf = new byte[len / 4 * 3 + 3];
    int obufcount = 0;
    for (int i = off; i < off + len; i++) {
      char ch = (char) data[i];
      if (ch == S_BASE64PAD
          || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
        ibuf[ibufcount++] = ch;
        if (ibufcount == ibuf.length) {
          ibufcount = 0;
          obufcount += base64Decode0(ibuf, obuf, obufcount);
        }
      }
    }
    if (obufcount == obuf.length) {
      return obuf;
    }
    byte[] ret = new byte[obufcount];
    System.arraycopy(obuf, 0, ret, 0, obufcount);
    return ret;
  }
  
  public static void base64Decode(char[] data, int off, int len,
                                  OutputStream ostream) throws IOException {
    char[] ibuf = new char[4];
    int ibufcount = 0;
    byte[] obuf = new byte[3];
    for (int i = off; i < off + len; i++) {
      char ch = data[i];
      if (ch == S_BASE64PAD
          || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
        ibuf[ibufcount++] = ch;
        if (ibufcount == ibuf.length) {
          ibufcount = 0;
          int obufcount = base64Decode0(ibuf, obuf, 0);
          ostream.write(obuf, 0, obufcount);
        }
      }
    }
  }
  
  public static void base64Decode(String data, OutputStream ostream) throws
      IOException {
    char[] ibuf = new char[4];
    int ibufcount = 0;
    byte[] obuf = new byte[3];
    for (int i = 0; i < data.length(); i++) {
      char ch = data.charAt(i);
      if (ch == S_BASE64PAD
          || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
        ibuf[ibufcount++] = ch;
        if (ibufcount == ibuf.length) {
          ibufcount = 0;
          int obufcount = base64Decode0(ibuf, obuf, 0);
          ostream.write(obuf, 0, obufcount);
        }
      }
    }
  }
  
  
  public static String base64Encode(byte[] data) {
    return base64Encode(data, 0, data.length);
  }
  
  
  public static String base64Encode(byte[] data, int off, int len) {
    if (len <= 0) {
      return "";
    }
    char[] out = new char[len / 3 * 4 + 4];
    int rindex = off;
    int windex = 0;
    int rest = len;
    while (rest >= 3) {
      int i = ( (data[rindex] & 0xff) << 16)
          + ( (data[rindex + 1] & 0xff) << 8)
          + (data[rindex + 2] & 0xff);
      out[windex++] = S_BASE64CHAR[i >> 18];
      out[windex++] = S_BASE64CHAR[ (i >> 12) & 0x3f];
      out[windex++] = S_BASE64CHAR[ (i >> 6) & 0x3f];
      out[windex++] = S_BASE64CHAR[i & 0x3f];
      rindex += 3;
      rest -= 3;
    }
    if (rest == 1) {
      int i = data[rindex] & 0xff;
      out[windex++] = S_BASE64CHAR[i >> 2];
      out[windex++] = S_BASE64CHAR[ (i << 4) & 0x3f];
      out[windex++] = S_BASE64PAD;
      out[windex++] = S_BASE64PAD;
    }
    else if (rest == 2) {
      int i = ( (data[rindex] & 0xff) << 8) + (data[rindex + 1] & 0xff);
      out[windex++] = S_BASE64CHAR[i >> 10];
      out[windex++] = S_BASE64CHAR[ (i >> 4) & 0x3f];
      out[windex++] = S_BASE64CHAR[ (i << 2) & 0x3f];
      out[windex++] = S_BASE64PAD;
    }
    return new String(out, 0, windex);
  }
  
  
  public static void base64Encode(byte[] data, int off, int len,
                                  OutputStream ostream) throws IOException {
    if (len <= 0) {
      return;
    }
    byte[] out = new byte[4];
    int rindex = off;
    int rest = len - off;
    while (rest >= 3) {
      int i = ( (data[rindex] & 0xff) << 16)
          + ( (data[rindex + 1] & 0xff) << 8)
          + (data[rindex + 2] & 0xff);
      out[0] = (byte) S_BASE64CHAR[i >> 18];
      out[1] = (byte) S_BASE64CHAR[ (i >> 12) & 0x3f];
      out[2] = (byte) S_BASE64CHAR[ (i >> 6) & 0x3f];
      out[3] = (byte) S_BASE64CHAR[i & 0x3f];
      ostream.write(out, 0, 4);
      rindex += 3;
      rest -= 3;
    }
    if (rest == 1) {
      int i = data[rindex] & 0xff;
      out[0] = (byte) S_BASE64CHAR[i >> 2];
      out[1] = (byte) S_BASE64CHAR[ (i << 4) & 0x3f];
      out[2] = (byte) S_BASE64PAD;
      out[3] = (byte) S_BASE64PAD;
      ostream.write(out, 0, 4);
    }
    else if (rest == 2) {
      int i = ( (data[rindex] & 0xff) << 8) + (data[rindex + 1] & 0xff);
      out[0] = (byte) S_BASE64CHAR[i >> 10];
      out[1] = (byte) S_BASE64CHAR[ (i >> 4) & 0x3f];
      out[2] = (byte) S_BASE64CHAR[ (i << 2) & 0x3f];
      out[3] = (byte) S_BASE64PAD;
      ostream.write(out, 0, 4);
    }
  }
  
  
  public static void base64Encode(byte[] data, int off, int len, Writer writer) throws
      IOException {
    if (len <= 0) {
      return;
    }
    char[] out = new char[4];
    int rindex = off;
    int rest = len - off;
    int output = 0;
    while (rest >= 3) {
      int i = ( (data[rindex] & 0xff) << 16)
          + ( (data[rindex + 1] & 0xff) << 8)
          + (data[rindex + 2] & 0xff);
      out[0] = S_BASE64CHAR[i >> 18];
      out[1] = S_BASE64CHAR[ (i >> 12) & 0x3f];
      out[2] = S_BASE64CHAR[ (i >> 6) & 0x3f];
      out[3] = S_BASE64CHAR[i & 0x3f];
      writer.write(out, 0, 4);
      rindex += 3;
      rest -= 3;
      output += 4;
      if (output % 76 == 0) {
        writer.write("\n");
      }
    }
    if (rest == 1) {
      int i = data[rindex] & 0xff;
      out[0] = S_BASE64CHAR[i >> 2];
      out[1] = S_BASE64CHAR[ (i << 4) & 0x3f];
      out[2] = S_BASE64PAD;
      out[3] = S_BASE64PAD;
      writer.write(out, 0, 4);
    }
    else if (rest == 2) {
      int i = ( (data[rindex] & 0xff) << 8) + (data[rindex + 1] & 0xff);
      out[0] = S_BASE64CHAR[i >> 10];
      out[1] = S_BASE64CHAR[ (i >> 4) & 0x3f];
      out[2] = S_BASE64CHAR[ (i << 2) & 0x3f];
      out[3] = S_BASE64PAD;
      writer.write(out, 0, 4);
    }
  }
}





byte to be tested if it is Base64 alphabet

    
/*   Copyright 2004 The Apache Software Foundation
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *  limitations under the License.
 */
//xmlbeans
import java.io.UnsupportedEncodingException;
/**
 * format validation
 *
 * This class encodes/decodes hexadecimal data
 * @author Jeffrey Rodriguez
 * @version $Id: HexBin.java 125124 2005-01-14 00:23:54Z kkrouse $
 */
public class Main {
  static private final int  BASELENGTH   = 255;
  static private final int  LOOKUPLENGTH = 16;
  static private byte [] hexNumberTable    = new byte[BASELENGTH];
  static private byte [] lookUpHexAlphabet = new byte[LOOKUPLENGTH];

  static {
      for (int i = 0; i<BASELENGTH; i++ ) {
          hexNumberTable[i] = -1;
      }
      for ( int i = "9"; i >= "0"; i--) {
          hexNumberTable[i] = (byte) (i-"0");
      }
      for ( int i = "F"; i>= "A"; i--) {
          hexNumberTable[i] = (byte) ( i-"A" + 10 );
      }
      for ( int i = "f"; i>= "a"; i--) {
         hexNumberTable[i] = (byte) ( i-"a" + 10 );
      }
      for(int i = 0; i<10; i++ )
          lookUpHexAlphabet[i] = (byte) ("0"+i );
      for(int i = 10; i<=15; i++ )
          lookUpHexAlphabet[i] = (byte) ("A"+i -10);
  }
  /**
   * byte to be tested if it is Base64 alphabet
   *
   * @param octect
   * @return
   */
  static boolean isHex(byte octect) {
      return (hexNumberTable[octect] != -1);
  }
}





Codes number up to radix 62

    
/*
 * Copyright 2000,2005 wingS development team.
 *
 * This file is part of wingS (http://wingsframework.org).
 *
 * wingS is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1
 * of the License, or (at your option) any later version.
 *
 * Please see COPYING for the complete licence.
 */
import java.util.StringTokenizer;
/**
 * Some string manipulation utilities.
 *
 * @author 
 */
public class StringUtil {
  private final static char[] ALPHAS = {
      "a", "b",
      "c", "d", "e", "f", "g", "h",
      "i", "j", "k", "l", "m", "n",
      "o", "p", "q", "r", "s", "t",
      "u", "v", "w", "x", "y", "z",
  };
  /**
   * All possible digits for representing a number as a String
   * This is conservative and does not include "special"
   * characters since some browsers don"t handle them right.
   * The IE for instance seems to be case insensitive in class
   * names for CSSs. Grrr.
   */
  private final static char[] DIGITS = {
      "0", "1", "2", "3", "4", "5",
      "6", "7", "8", "9", "a", "b",
      "c", "d", "e", "f", "g", "h",
      "i", "j", "k", "l", "m", "n",
      "o", "p", "q", "r", "s", "t",
      "u", "v", "w", "x", "y", "z",
      /* This %@&!-IE is case insensitive for certain
       * URLs and IDs
       * "A" , "B" ,
       * "C" , "D" , "E" , "F" , "G" , "H" ,
       * "I" , "J" , "K" , "L" , "M" , "N" ,
       * "O" , "P" , "Q" , "R" , "S" , "T" ,
       * "U" , "V" , "W" , "X" , "Y" , "Z"
       */
  };
  public static final int MAX_RADIX = DIGITS.length;
  /**
   * Codes number up to radix 62.
   * Note, this method is only public for backward compatiblity. don"t
   * use it.
   *
   * @param minDigits returns a string with a least minDigits digits
   */
  public static String toString(long i, int radix, int minDigits) {
      char[] buf = new char[65];
      radix = Math.min(Math.abs(radix), MAX_RADIX);
      minDigits = Math.min(buf.length - 1, Math.abs(minDigits));

      int charPos = buf.length - 1;
      boolean negative = (i < 0);
      if (negative) {
          i = -i;
      }
      while (i >= radix) {
          buf[charPos--] = DIGITS[(int) (i % radix)];
          i /= radix;
      }
      buf[charPos] = DIGITS[(int) i];
      // if minimum length of the result string is set, pad it with the
      // zero-representation (that is: "0")
      while (charPos > buf.length - minDigits)
          buf[--charPos] = DIGITS[0];
      if (negative) {
          buf[--charPos] = "-";
      }
      return new String(buf, charPos, buf.length - charPos);
  }
  
}





Converting hexadecimal strings

    
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/* $Id$ */

/**
 * Provides helper functions for converting hexadecimal strings.
 */
public class HexUtil {
    private static final char[] DIGITS = 
        {"0", "1", "2", "3", "4", "5", "6", "7",
         "8", "9", "A", "B", "C", "D", "E", "F"};
    /**
     * Converts a byte array to a hexadecimal String
     * @param data the data to encode
     * @return String the resulting String
     */
    public static final String toHex(byte[] data) {
        final StringBuffer sb = new StringBuffer(data.length * 2);
        for (int i = 0; i < data.length; i++) {
            sb.append(DIGITS[(data[i] >>> 4) & 0x0F]);
            sb.append(DIGITS[data[i] & 0x0F]);
        }
        return sb.toString();
    }
    
}





Convert to hex from byte arrays and back

    
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * Used to convert to hex from byte arrays and back.
 * 
 * @version $Revision: 1.2 $
 */
public final class HexSupport {
    
    private static final String[] HEX_TABLE = new String[]{
        "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0a", "0b", "0c", "0d", "0e", "0f",
        "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1a", "1b", "1c", "1d", "1e", "1f",
        "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2a", "2b", "2c", "2d", "2e", "2f",
        "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3a", "3b", "3c", "3d", "3e", "3f",
        "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4a", "4b", "4c", "4d", "4e", "4f",
        "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5a", "5b", "5c", "5d", "5e", "5f",
        "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6a", "6b", "6c", "6d", "6e", "6f",
        "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7a", "7b", "7c", "7d", "7e", "7f",
        "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8a", "8b", "8c", "8d", "8e", "8f",
        "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9a", "9b", "9c", "9d", "9e", "9f",
        "a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "a8", "a9", "aa", "ab", "ac", "ad", "ae", "af",
        "b0", "b1", "b2", "b3", "b4", "b5", "b6", "b7", "b8", "b9", "ba", "bb", "bc", "bd", "be", "bf",
        "c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7", "c8", "c9", "ca", "cb", "cc", "cd", "ce", "cf",
        "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "da", "db", "dc", "dd", "de", "df",
        "e0", "e1", "e2", "e3", "e4", "e5", "e6", "e7", "e8", "e9", "ea", "eb", "ec", "ed", "ee", "ef",
        "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "fa", "fb", "fc", "fd", "fe", "ff",
    };
    private static final int[] INT_OFFSETS = new int[]{
      24,16,8,0
    };
    
    private HexSupport() {
    }
    
    /**
     * @param hex
     * @return
     */
    public static byte[] toBytesFromHex(String hex) {
        byte rc[] = new byte[hex.length() / 2];
        for (int i = 0; i < rc.length; i++) {
            String h = hex.substring(i * 2, i * 2 + 2);
            int x = Integer.parseInt(h, 16);
            rc[i] = (byte) x;
        }
        return rc;
    }
    /**
     * @param bytes
     * @return
     */
    public static String toHexFromBytes(byte[] bytes) {
        StringBuffer rc = new StringBuffer(bytes.length * 2);
        for (int i = 0; i < bytes.length; i++) {
            rc.append(HEX_TABLE[0xFF & bytes[i]]);
        }
        return rc.toString();
    }
    /**
     * 
     * @param value 
     * @param trim if the leading 0"s should be trimmed off.
     * @return
     */
    public static String toHexFromInt(int value, boolean trim) {
        StringBuffer rc = new StringBuffer(INT_OFFSETS.length*2);
        for (int i = 0; i < INT_OFFSETS.length; i++) {
          int b = 0xFF & (value>>INT_OFFSETS[i]);
          if( !(trim && b == 0) ) { 
            rc.append(HEX_TABLE[b]);
            trim=false;
          }
        }
        return rc.toString();
    }
}





Decodes Base64 data into octects

    
/*   Copyright 2004 The Apache Software Foundation
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *  limitations under the License.
 */

import java.io.UnsupportedEncodingException;
/**
 * This class provides encode/decode for RFC 2045 Base64 as
 * defined by RFC 2045, N. Freed and N. Borenstein.
 * RFC 2045: Multipurpose Internet Mail Extensions (MIME)
 * Part One: Format of Internet Message Bodies. Reference
 * 1996 Available at: http://www.ietf.org/rfc/rfc2045.txt
 * This class is used by XML Schema binary format validation
 *
 * This implementation does not encode/decode streaming
 * data. You need the data that you will encode/decode
 * already on a byte arrray.
 * 
 * 
 * From xmlbeans
 * @author Jeffrey Rodriguez
 * @author Sandy Gao
 * @version $Id: Base64.java 111285 2004-12-08 16:54:26Z cezar $
 */
public final class  Base64 {
    static private final int  BASELENGTH         = 255;
    static private final int  LOOKUPLENGTH       = 64;
    static private final int  TWENTYFOURBITGROUP = 24;
    static private final int  EIGHTBIT           = 8;
    static private final int  SIXTEENBIT         = 16;
    //static private final int  SIXBIT             = 6;
    static private final int  FOURBYTE           = 4;
    static private final int  SIGN               = -128;
    static private final byte PAD                = ( byte ) "=";
    static private final boolean fDebug          = false;
    static private byte [] base64Alphabet        = new byte[BASELENGTH];
    static private byte [] lookUpBase64Alphabet  = new byte[LOOKUPLENGTH];
    static {
        for (int i = 0; i<BASELENGTH; i++) {
            base64Alphabet[i] = -1;
        }
        for (int i = "Z"; i >= "A"; i--) {
            base64Alphabet[i] = (byte) (i-"A");
        }
        for (int i = "z"; i>= "a"; i--) {
            base64Alphabet[i] = (byte) ( i-"a" + 26);
        }
        for (int i = "9"; i >= "0"; i--) {
            base64Alphabet[i] = (byte) (i-"0" + 52);
        }
        base64Alphabet["+"]  = 62;
        base64Alphabet["/"]  = 63;
        for (int i = 0; i<=25; i++)
            lookUpBase64Alphabet[i] = (byte) ("A"+i );
        for (int i = 26,  j = 0; i<=51; i++, j++)
            lookUpBase64Alphabet[i] = (byte) ("a"+ j );
        for (int i = 52,  j = 0; i<=61; i++, j++)
            lookUpBase64Alphabet[i] = (byte) ("0" + j );
        lookUpBase64Alphabet[62] = (byte) "+";
        lookUpBase64Alphabet[63] = (byte) "/";
    }
    protected static boolean isWhiteSpace(byte octect) {
        return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
    }
    protected static boolean isPad(byte octect) {
        return (octect == PAD);
    }
    protected static boolean isData(byte octect) {
        return (base64Alphabet[octect] != -1);
    }
    protected static boolean isBase64(byte octect) {
        return (isWhiteSpace(octect) || isPad(octect) || isData(octect));
    }
    /**
     * Encodes hex octects into Base64
     *
     * @param binaryData Array containing binaryData
     * @return Encoded Base64 array
     */
    public static byte[] encode(byte[] binaryData) {
        if (binaryData == null)
            return null;
        int      lengthDataBits    = binaryData.length*EIGHTBIT;
        int      fewerThan24bits   = lengthDataBits%TWENTYFOURBITGROUP;
        int      numberTriplets    = lengthDataBits/TWENTYFOURBITGROUP;
        byte     encodedData[]     = null;
        if (fewerThan24bits != 0) //data not divisible by 24 bit
            encodedData = new byte[ (numberTriplets + 1 )*4  ];
        else // 16 or 8 bit
            encodedData = new byte[ numberTriplets*4 ];
        byte k=0, l=0, b1=0,b2=0,b3=0;
        int encodedIndex = 0;
        int dataIndex   = 0;
        int i           = 0;
        if (fDebug) {
            System.out.println("number of triplets = " + numberTriplets );
        }
        for (i = 0; i<numberTriplets; i++) {
            dataIndex = i*3;
            b1 = binaryData[dataIndex];
            b2 = binaryData[dataIndex + 1];
            b3 = binaryData[dataIndex + 2];
            if (fDebug) {
                System.out.println( "b1= " + b1 +", b2= " + b2 + ", b3= " + b3 );
            }
            l  = (byte)(b2 & 0x0f);
            k  = (byte)(b1 & 0x03);
            encodedIndex = i*4;
            byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
            byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
            byte val3 = ((b3 & SIGN)==0)?(byte)(b3>>6):(byte)((b3)>>6^0xfc);
            encodedData[encodedIndex]   = lookUpBase64Alphabet[ val1 ];
            if (fDebug) {
                System.out.println( "val2 = " + val2 );
                System.out.println( "k4   = " + (k<<4));
                System.out.println( "vak  = " + (val2 | (k<<4)));
            }
            encodedData[encodedIndex+1] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
            encodedData[encodedIndex+2] = lookUpBase64Alphabet[ (l <<2 ) | val3 ];
            encodedData[encodedIndex+3] = lookUpBase64Alphabet[ b3 & 0x3f ];
        }
        // form integral number of 6-bit groups
        dataIndex    = i*3;
        encodedIndex = i*4;
        if (fewerThan24bits == EIGHTBIT) {
            b1 = binaryData[dataIndex];
            k = (byte) ( b1 &0x03 );
            if (fDebug) {
                System.out.println("b1=" + b1);
                System.out.println("b1<<2 = " + (b1>>2) );
            }
            byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
            encodedData[encodedIndex]     = lookUpBase64Alphabet[ val1 ];
            encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ k<<4 ];
            encodedData[encodedIndex + 2] = PAD;
            encodedData[encodedIndex + 3] = PAD;
        } else if (fewerThan24bits == SIXTEENBIT) {
            b1 = binaryData[dataIndex];
            b2 = binaryData[dataIndex +1 ];
            l = ( byte ) ( b2 &0x0f );
            k = ( byte ) ( b1 &0x03 );
            byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
            byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
            encodedData[encodedIndex]     = lookUpBase64Alphabet[ val1 ];
            encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
            encodedData[encodedIndex + 2] = lookUpBase64Alphabet[ l<<2 ];
            encodedData[encodedIndex + 3] = PAD;
        }
        return encodedData;
    }
    /**
     * Decodes Base64 data into octects
     *
     * @param base64Data Byte array containing Base64 data
     * @return Array containind decoded data.
     */
    public static byte[] decode(byte[] base64Data) {
        if (base64Data == null)
            return null;
        // remove white spaces
        base64Data = removeWhiteSpace(base64Data);
        if (base64Data.length%FOURBYTE != 0) {
            return null;//should be divisible by four
        }
        int      numberQuadruple    = (base64Data.length/FOURBYTE );
        if (numberQuadruple == 0)
            return new byte[0];
        byte     decodedData[]      = null;
        byte     b1=0,b2=0,b3=0, b4=0;//, marker0=0, marker1=0;
        byte     d1=0,d2=0,d3=0,d4=0;
        // Throw away anything not in normalizedBase64Data
        // Adjust size
        int i = 0;
        int encodedIndex = 0;
        int dataIndex    = 0;
        decodedData      = new byte[ (numberQuadruple)*3];
        for (; i<numberQuadruple-1; i++) {
            if (!isData( (d1 = base64Data[dataIndex++]) )||
                !isData( (d2 = base64Data[dataIndex++]) )||
                !isData( (d3 = base64Data[dataIndex++]) )||
                !isData( (d4 = base64Data[dataIndex++]) ))
                return null;//if found "no data" just return null
            b1 = base64Alphabet[d1];
            b2 = base64Alphabet[d2];
            b3 = base64Alphabet[d3];
            b4 = base64Alphabet[d4];
            decodedData[encodedIndex++] = (byte)(  b1 <<2 | b2>>4 ) ;
            decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
            decodedData[encodedIndex++] = (byte)( b3<<6 | b4 );
        }
        if (!isData( (d1 = base64Data[dataIndex++]) ) ||
            !isData( (d2 = base64Data[dataIndex++]) )) {
            return null;//if found "no data" just return null
        }
        b1 = base64Alphabet[d1];
        b2 = base64Alphabet[d2];
        d3 = base64Data[dataIndex++];
        d4 = base64Data[dataIndex++];
        if (!isData( (d3 ) ) ||
            !isData( (d4 ) )) {//Check if they are PAD characters
            if (isPad( d3 ) && isPad( d4)) {               //Two PAD e.g. 3c[Pad][Pad]
                if ((b2 & 0xf) != 0)//last 4 bits should be zero
                    return null;
                byte[] tmp = new byte[ i*3 + 1 ];
                System.arraycopy( decodedData, 0, tmp, 0, i*3 );
                tmp[encodedIndex]   = (byte)(  b1 <<2 | b2>>4 ) ;
                return tmp;
            } else if (!isPad( d3) && isPad(d4)) {               //One PAD  e.g. 3cQ[Pad]
                b3 = base64Alphabet[ d3 ];
                if ((b3 & 0x3 ) != 0)//last 2 bits should be zero
                    return null;
                byte[] tmp = new byte[ i*3 + 2 ];
                System.arraycopy( decodedData, 0, tmp, 0, i*3 );
                tmp[encodedIndex++] = (byte)(  b1 <<2 | b2>>4 );
                tmp[encodedIndex]   = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
                return tmp;
            } else {
                return null;//an error  like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data
            }
        } else { //No PAD e.g 3cQl
            b3 = base64Alphabet[ d3 ];
            b4 = base64Alphabet[ d4 ];
            decodedData[encodedIndex++] = (byte)(  b1 <<2 | b2>>4 ) ;
            decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
            decodedData[encodedIndex++] = (byte)( b3<<6 | b4 );
        }
        return decodedData;
    }
//    /**
//     * Decodes Base64 data into octects
//     *
//     * @param base64Data String containing Base64 data
//     * @return string containing decoded data.
//     */
//    public static String decode(String base64Data) {
//        if (base64Data == null)
//            return null;
//
//        byte[] decoded = null;
//        try {
//            decoded = decode(base64Data.getBytes("utf-8"));
//        }
//        catch(UnsupportedEncodingException e) {
//        }
//        finally {
//            return decoded == null ? null : new String(decoded);
//        }
//    }
//
//    /**
//     * Encodes octects (using utf-8) into Base64 data
//     *
//     * @param binaryData String containing Hex data
//     * @return string containing decoded data.
//     */
//    public static String encode(String binaryData) {
//        if (binaryData == null)
//            return null;
//
//        byte[] encoded = null;
//         try {
//          encoded = encode(binaryData.getBytes("utf-8"));
//        }
//        catch(UnsupportedEncodingException e) {}
//        finally {
//            return encoded == null ? null : new String(encoded);
//        }
//    }
    /**
     * remove WhiteSpace from MIME containing encoded Base64 data.
     *
     * @param data  the byte array of base64 data (with WS)
     * @return      the byte array of base64 data (without WS)
     */
    protected static byte[] removeWhiteSpace(byte[] data) {
        if (data == null)
            return null;
        // count characters that"s not whitespace
        int newSize = 0;
        int len = data.length;
        for (int i = 0; i < len; i++) {
            if (!isWhiteSpace(data[i]))
                newSize++;
        }
        // if no whitespace, just return the input array
        if (newSize == len)
            return data;
        // create the array to return
        byte[] newArray = new byte[newSize];
        int j = 0;
        for (int i = 0; i < len; i++) {
            if (!isWhiteSpace(data[i]))
                newArray[j++] = data[i];
        }
        return newArray;
    }
}





Encode and decode data in Base64 format as described in RFC 1521

    
/**************************************************************************
 *
 * A Base64 Encoder/Decoder.
 *
 * This class is used to encode and decode data in Base64 format
 * as described in RFC 1521.
 *
 * <p>
 * Copyright 2003: Christian d"Heureuse, Inventec Informatik AG, Switzerland.<br>
 * License: This is "Open Source" software and released under the <br>
 *
 * <p>
 * Version history:<br>
 * 2003-07-22 Christian d"Heureuse (chdh): Module created.<br>
 * 2005-08-11 chdh: Lincense changed from GPL to LGPL.
 *
 **************************************************************************/

public class Base64Coder {
  //   Mapping table from 6-bit nibbles to Base64 characters.
  private static char[] map1 = new char[64];
  static {
    int i = 0;
    for (char c = "A"; c <= "Z"; c++)
      map1[i++] = c;
    for (char c = "a"; c <= "z"; c++)
      map1[i++] = c;
    for (char c = "0"; c <= "9"; c++)
      map1[i++] = c;
    map1[i++] = "+";
    map1[i++] = "/";
  }
  //   Mapping table from Base64 characters to 6-bit nibbles.
  private static byte[] map2 = new byte[128];
  static {
    for (int i = 0; i < map2.length; i++)
      map2[i] = -1;
    for (int i = 0; i < 64; i++)
      map2[map1[i]] = (byte) i;
  }
  /**
   * Encodes a string into Base64 format.
   * No blanks or line breaks are inserted.
   * @param s  a String to be encoded.
   * @return   A String with the Base64 encoded data.
   */
  public static String encode(String s) {
    return new String(encode(s.getBytes()));
  }
  /**
   * Encodes a byte array into Base64 format.
   * No blanks or line breaks are inserted.
   * @param in  an array containing the data bytes to be encoded.
   * @return    A character array with the Base64 encoded data.
   */
  public static char[] encode(byte[] in) {
    int iLen = in.length;
    int oDataLen = (iLen * 4 + 2) / 3; // output length without padding
    int oLen = ((iLen + 2) / 3) * 4; // output length including padding
    char[] out = new char[oLen];
    int ip = 0;
    int op = 0;
    while (ip < iLen) {
      int i0 = in[ip++] & 0xff;
      int i1 = ip < iLen ? in[ip++] & 0xff : 0;
      int i2 = ip < iLen ? in[ip++] & 0xff : 0;
      int o0 = i0 >>> 2;
      int o1 = ((i0 & 3) << 4) | (i1 >>> 4);
      int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6);
      int o3 = i2 & 0x3F;
      out[op++] = map1[o0];
      out[op++] = map1[o1];
      out[op] = op < oDataLen ? map1[o2] : "=";
      op++;
      out[op] = op < oDataLen ? map1[o3] : "=";
      op++;
    }
    return out;
  }
  /**
   * Decodes a Base64 string.
   * @param s  a Base64 String to be decoded.
   * @return   A String containing the decoded data.
   * @throws   IllegalArgumentException if the input is not valid Base64 encoded data.
   */
  public static String decode(String s) {
    return new String(decode(s.toCharArray()));
  }
  /**
   * Decodes Base64 data.
   * No blanks or line breaks are allowed within the Base64 encoded data.
   * @param in  a character array containing the Base64 encoded data.
   * @return    An array containing the decoded data bytes.
   * @throws    IllegalArgumentException if the input is not valid Base64 encoded data.
   */
  public static byte[] decode(char[] in) {
    int iLen = in.length;
    if (iLen % 4 != 0)
      throw new IllegalArgumentException(
          "Length of Base64 encoded input string is not a multiple of 4.");
    while (iLen > 0 && in[iLen - 1] == "=")
      iLen--;
    int oLen = (iLen * 3) / 4;
    byte[] out = new byte[oLen];
    int ip = 0;
    int op = 0;
    while (ip < iLen) {
      int i0 = in[ip++];
      int i1 = in[ip++];
      int i2 = ip < iLen ? in[ip++] : "A";
      int i3 = ip < iLen ? in[ip++] : "A";
      if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127)
        throw new IllegalArgumentException(
            "Illegal character in Base64 encoded data.");
      int b0 = map2[i0];
      int b1 = map2[i1];
      int b2 = map2[i2];
      int b3 = map2[i3];
      if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0)
        throw new IllegalArgumentException(
            "Illegal character in Base64 encoded data.");
      int o0 = (b0 << 2) | (b1 >>> 4);
      int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2);
      int o2 = ((b2 & 3) << 6) | b3;
      out[op++] = (byte) o0;
      if (op < oLen)
        out[op++] = (byte) o1;
      if (op < oLen)
        out[op++] = (byte) o2;
    }
    return out;
  }
}





Encode and decode integers, times, and internationalized strings to and from popular binary formats

    
/* encdec - encode and decode integers, times, and
 * internationalized strings to and from popular binary formats
 * http://www.ioplex.ru/~miallen/encdec/
 * Copyright (c) 2003 Michael B. Allen <mballen@erols.ru>
 *
 * The GNU Library General Public License
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 * 
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
 * MA 02111-1307, USA
 */

import java.util.Date;
import java.io.IOException;
public class Encdec {
    public static final long MILLISECONDS_BETWEEN_1970_AND_1601 = 11644473600000L;
    public static final long SEC_BETWEEEN_1904_AND_1970 = 2082844800L;
    public static final int TIME_1970_SEC_32BE = 1;
    public static final int TIME_1970_SEC_32LE = 2;
    public static final int TIME_1904_SEC_32BE = 3;
    public static final int TIME_1904_SEC_32LE = 4;
    public static final int TIME_1601_NANOS_64LE = 5;
    public static final int TIME_1601_NANOS_64BE = 6;
    public static final int TIME_1970_MILLIS_64BE = 7;
    public static final int TIME_1970_MILLIS_64LE = 8;
    /* Encode integers
     */
    public static int enc_uint16be( short s, byte[] dst, int di ) {
        dst[di++] = (byte)((s >> 8) & 0xFF);
        dst[di] = (byte)(s & 0xFF);
        return 2;
    }
    public static int enc_uint32be( int i, byte[] dst, int di ) {
        dst[di++] = (byte)((i >> 24) & 0xFF);
        dst[di++] = (byte)((i >> 16) & 0xFF);
        dst[di++] = (byte)((i >> 8) & 0xFF);
        dst[di] = (byte)(i & 0xFF);
        return 4;
    }
    public static int enc_uint16le( short s, byte[] dst, int di )
    {
        dst[di++] = (byte)(s & 0xFF);
        dst[di] = (byte)((s >> 8) & 0xFF);
        return 2;
    }
    public static int enc_uint32le( int i, byte[] dst, int di )
    {
        dst[di++] = (byte)(i & 0xFF);
        dst[di++] = (byte)((i >> 8) & 0xFF);
        dst[di++] = (byte)((i >> 16) & 0xFF);
        dst[di] = (byte)((i >> 24) & 0xFF);
        return 4;
    }
    /* Decode integers
     */
    public static short dec_uint16be( byte[] src, int si )
    {
        return (short)(((src[si] & 0xFF) << 8) | (src[si + 1] & 0xFF));
    }
    public static int dec_uint32be( byte[] src, int si )
    {
        return ((src[si] & 0xFF) << 24) | ((src[si + 1] & 0xFF) << 16) |
               ((src[si + 2] & 0xFF) << 8) | (src[si + 3] & 0xFF);
    }
    public static short dec_uint16le( byte[] src, int si )
    {
        return (short)((src[si] & 0xFF) | ((src[si + 1] & 0xFF) << 8));
    }
    public static int dec_uint32le( byte[] src, int si )
    {
        return (src[si] & 0xFF) | ((src[si + 1] & 0xFF) << 8) |
               ((src[si + 2] & 0xFF) << 16) | ((src[si + 3] & 0xFF) << 24);
    }
    /* Encode and decode 64 bit integers
     */
    public static int enc_uint64be( long l, byte[] dst, int di )
    {
        enc_uint32be( (int)(l & 0xFFFFFFFFL), dst, di + 4 );
        enc_uint32be( (int)(( l >> 32L ) & 0xFFFFFFFFL), dst, di );
        return 8;
    }
    public static int enc_uint64le( long l, byte[] dst, int di )
    {
        enc_uint32le( (int)(l & 0xFFFFFFFFL), dst, di );
        enc_uint32le( (int)(( l >> 32L ) & 0xFFFFFFFFL), dst, di + 4 );
        return 8;
    }
    public static long dec_uint64be( byte[] src, int si )
    {
        long l;
        l = dec_uint32be( src, si ) & 0xFFFFFFFFL;
        l <<= 32L;
        l |= dec_uint32be( src, si + 4 ) & 0xFFFFFFFFL;
        return l;
    }
    public static long dec_uint64le( byte[] src, int si )
    {
        long l;
        l = dec_uint32le( src, si + 4 ) & 0xFFFFFFFFL;
        l <<= 32L;
        l |= dec_uint32le( src, si ) & 0xFFFFFFFFL;
        return l;
    }
    /* Encode floats
     */
    public static int enc_floatle( float f, byte[] dst, int di )
    {
        return enc_uint32le( Float.floatToIntBits( f ), dst, di );
    }
    public static int enc_floatbe( float f, byte[] dst, int di )
    {
        return enc_uint32be( Float.floatToIntBits( f ), dst, di );
    }
    /* Decode floating point numbers
     */
    public static float dec_floatle( byte[] src, int si )
    {
        return Float.intBitsToFloat( dec_uint32le( src, si ));
    }
    public static float dec_floatbe( byte[] src, int si )
    {
        return Float.intBitsToFloat( dec_uint32be( src, si ));
    }
    /* Encode and decode doubles
     */
    public static int enc_doublele( double d, byte[] dst, int di )
    {
        return enc_uint64le( Double.doubleToLongBits( d ), dst, di );
    }
    public static int enc_doublebe( double d, byte[] dst, int di )
    {
        return enc_uint64be( Double.doubleToLongBits( d ), dst, di );
    }
    public static double dec_doublele( byte[] src, int si )
    {
        return Double.longBitsToDouble( dec_uint64le( src, si ));
    }
    public static double dec_doublebe( byte[] src, int si )
    {
        return Double.longBitsToDouble( dec_uint64be( src, si ));
    }
    /* Encode times
     */
    public static int enc_time( Date date, byte[] dst, int di, int enc )
    {
        long t;
        switch( enc ) {
            case TIME_1970_SEC_32BE:
                return enc_uint32be( (int)(date.getTime() / 1000L), dst, di );
            case TIME_1970_SEC_32LE:
                return enc_uint32le( (int)(date.getTime() / 1000L), dst, di );
            case TIME_1904_SEC_32BE:
                return enc_uint32be( (int)((date.getTime() / 1000L +
                    SEC_BETWEEEN_1904_AND_1970) & 0xFFFFFFFF), dst, di );
            case TIME_1904_SEC_32LE:
                return enc_uint32le( (int)((date.getTime() / 1000L +
                    SEC_BETWEEEN_1904_AND_1970) & 0xFFFFFFFF), dst, di );
            case TIME_1601_NANOS_64BE:
                t = (date.getTime() + MILLISECONDS_BETWEEN_1970_AND_1601) * 10000L;
                return enc_uint64be( t, dst, di );
            case TIME_1601_NANOS_64LE:
                t = (date.getTime() + MILLISECONDS_BETWEEN_1970_AND_1601) * 10000L;
                return enc_uint64le( t, dst, di );
            case TIME_1970_MILLIS_64BE:
                return enc_uint64be( date.getTime(), dst, di );
            case TIME_1970_MILLIS_64LE:
                return enc_uint64le( date.getTime(), dst, di );
            default:
                throw new IllegalArgumentException( "Unsupported time encoding" );
        }
    }
    /* Decode times
     */
    public static Date dec_time( byte[] src, int si, int enc )
    {
        long t;
    
        switch( enc ) {
            case TIME_1970_SEC_32BE:
                return new Date( dec_uint32be( src, si ) * 1000L );
            case TIME_1970_SEC_32LE:
                return new Date( dec_uint32le( src, si ) * 1000L );
            case TIME_1904_SEC_32BE:
                return new Date((( dec_uint32be( src, si ) & 0xFFFFFFFFL) -
                    SEC_BETWEEEN_1904_AND_1970 ) * 1000L );
            case TIME_1904_SEC_32LE:
                return new Date((( dec_uint32le( src, si ) & 0xFFFFFFFFL) -
                    SEC_BETWEEEN_1904_AND_1970 ) * 1000L );
            case TIME_1601_NANOS_64BE:
                t = dec_uint64be( src, si );
                return new Date( t / 10000L - MILLISECONDS_BETWEEN_1970_AND_1601);
            case TIME_1601_NANOS_64LE:
                t = dec_uint64le( src, si );
                return new Date( t / 10000L - MILLISECONDS_BETWEEN_1970_AND_1601);
            case TIME_1970_MILLIS_64BE:
                return new Date( dec_uint64be( src, si ));
            case TIME_1970_MILLIS_64LE:
                return new Date( dec_uint64le( src, si ));
            default:
                throw new IllegalArgumentException( "Unsupported time encoding" );
        }
    }
    public static int enc_utf8( String str, byte[] dst, int di, int dlim ) throws IOException {
        int start = di, ch;
        int strlen = str.length();
        for( int i = 0; di < dlim && i < strlen; i++ ) {
            ch = str.charAt( i );
            if ((ch >= 0x0001) && (ch <= 0x007F)) {
                dst[di++] = (byte)ch;
            } else if (ch > 0x07FF) {
                if((dlim - di) < 3 ) {
                    break;
                }
                dst[di++] = (byte)(0xE0 | ((ch >> 12) & 0x0F)); 
                dst[di++] = (byte)(0x80 | ((ch >>  6) & 0x3F)); 
                dst[di++] = (byte)(0x80 | ((ch >>  0) & 0x3F)); 
            } else {
                if((dlim - di) < 2 ) {
                    break;
                }
                dst[di++] = (byte)(0xC0 | ((ch >>  6) & 0x1F)); 
                dst[di++] = (byte)(0x80 | ((ch >>  0) & 0x3F)); 
            }
        }
        return di - start;
    }
    public static String dec_utf8( byte[] src, int si, int slim ) throws IOException {
        char[] uni = new char[slim - si];
        int ui, ch;
        for( ui = 0; si < slim && (ch = src[si++] & 0xFF) != 0; ui++ ) {
            if( ch < 0x80 ) {
                uni[ui] = (char)ch;
            } else if((ch & 0xE0) == 0xC0 ) {
                if((slim - si) < 2 ) {
                    break;
                }
                uni[ui] = (char)((ch & 0x1F) << 6);
                ch = src[si++] & 0xFF;
                uni[ui] |= ch & 0x3F;
                if ((ch & 0xC0) != 0x80 || uni[ui] < 0x80 ) {
                    throw new IOException( "Invalid UTF-8 sequence" );
                }
            } else if((ch & 0xF0) == 0xE0 ) {
                if((slim - si) < 3 ) {
                    break;
                }
                uni[ui]  = (char)((ch & 0x0F) << 12);
                ch = src[si++] & 0xFF;
                if ((ch & 0xC0) != 0x80 ) {
                    throw new IOException( "Invalid UTF-8 sequence" );
                } else {
                    uni[ui] |= (ch & 0x3F) << 6;
                    ch = src[si++] & 0xFF;
                    uni[ui] |=  ch & 0x3F;
                    if ((ch & 0xC0) != 0x80 || uni[ui] < 0x800) {
                        throw new IOException( "Invalid UTF-8 sequence" );
                    }
                }
            } else {
                throw new IOException( "Unsupported UTF-8 sequence" );
            }
        }
        return new String( uni, 0, ui );
    }
    public static String dec_ucs2le( byte[] src, int si, int slim, char[] buf ) throws IOException {
        int bi;
        for( bi = 0; (si + 1) < slim; bi++, si += 2 ) {
            buf[bi] = (char)dec_uint16le( src, si );
            if( buf[bi] == "\0" ) {
                break;
            }
        }
        return new String( buf, 0, bi );
    }
}





Encode/decode for RFC 2045 Base64 as defined by RFC 2045

    
 
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * This class provides encode/decode for RFC 2045 Base64 as defined by
 * RFC 2045, N. Freed and N. Borenstein.  :
 * Multipurpose Internet Mail Extensions (MIME) Part One: Format of
 * Internet Message Bodies. Reference 1996
 *
 * @author Jeffrey Rodriguez
 * @version $Id: Base64.java 515 2008-03-17 21:02:23Z jfrederic.clere@jboss.ru $
 */
public final class  Base64
{
    static private final int  BASELENGTH         = 255;
    static private final int  LOOKUPLENGTH       = 64;
    static private final int  TWENTYFOURBITGROUP = 24;
    static private final int  EIGHTBIT           = 8;
    static private final int  SIXTEENBIT         = 16;
    static private final int  SIXBIT             = 6;
    static private final int  FOURBYTE           = 4;
    static private final int  SIGN               = -128;
    static private final byte PAD                = (byte) "=";
    static private byte [] base64Alphabet       = new byte[BASELENGTH];
    static private byte [] lookUpBase64Alphabet = new byte[LOOKUPLENGTH];
    //static private final Log log = LogSource.getInstance("org.apache.rumons.util.Base64");
    static
    {
        for (int i = 0; i < BASELENGTH; i++ )
        {
            base64Alphabet[i] = -1;
        }
        for (int i = "Z"; i >= "A"; i--)
        {
            base64Alphabet[i] = (byte) (i - "A");
        }
        for (int i = "z"; i>= "a"; i--)
        {
            base64Alphabet[i] = (byte) (i - "a" + 26);
        }
        for (int i = "9"; i >= "0"; i--)
        {
            base64Alphabet[i] = (byte) (i - "0" + 52);
        }
        base64Alphabet["+"]  = 62;
        base64Alphabet["/"]  = 63;
        for (int i = 0; i <= 25; i++ )
            lookUpBase64Alphabet[i] = (byte) ("A" + i);
        for (int i = 26,  j = 0; i <= 51; i++, j++ )
            lookUpBase64Alphabet[i] = (byte) ("a"+ j);
        for (int i = 52,  j = 0; i <= 61; i++, j++ )
            lookUpBase64Alphabet[i] = (byte) ("0" + j);
        lookUpBase64Alphabet[62] = (byte) "+";
        lookUpBase64Alphabet[63] = (byte) "/";
    }
    public static boolean isBase64( String isValidString )
    {
        return isArrayByteBase64(isValidString.getBytes());
    }
    public static boolean isBase64( byte octect )
    {
        //shall we ignore white space? JEFF??
        return (octect == PAD || base64Alphabet[octect] != -1);
    }
    public static boolean isArrayByteBase64( byte[] arrayOctect )
    {
        int length = arrayOctect.length;
        if (length == 0)
        {
            // shouldn"t a 0 length array be valid base64 data?
            // return false;
            return true;
        }
        for (int i=0; i < length; i++)
        {
            if ( !Base64.isBase64(arrayOctect[i]) )
                return false;
        }
        return true;
    }
    /**
     * Encodes hex octects into Base64.
     *
     * @param binaryData Array containing binary data to encode.
     * @return Base64-encoded data.
     */
    public static byte[] encode( byte[] binaryData )
    {
        int      lengthDataBits    = binaryData.length*EIGHTBIT;
        int      fewerThan24bits   = lengthDataBits%TWENTYFOURBITGROUP;
        int      numberTriplets    = lengthDataBits/TWENTYFOURBITGROUP;
        byte     encodedData[]     = null;

        if (fewerThan24bits != 0)
        {
            //data not divisible by 24 bit
            encodedData = new byte[ (numberTriplets + 1 ) * 4 ];
        }
        else
        {
            // 16 or 8 bit
            encodedData = new byte[ numberTriplets * 4 ];
        }
        byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
        int encodedIndex = 0;
        int dataIndex   = 0;
        int i           = 0;
        //log.debug("number of triplets = " + numberTriplets);
        for ( i = 0; i<numberTriplets; i++ )
        {
            dataIndex = i*3;
            b1 = binaryData[dataIndex];
            b2 = binaryData[dataIndex + 1];
            b3 = binaryData[dataIndex + 2];
            //log.debug("b1= " + b1 +", b2= " + b2 + ", b3= " + b3);
            l  = (byte)(b2 & 0x0f);
            k  = (byte)(b1 & 0x03);
            encodedIndex = i * 4;
            byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
            byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
            byte val3 = ((b3 & SIGN)==0)?(byte)(b3>>6):(byte)((b3)>>6^0xfc);
            encodedData[encodedIndex]   = lookUpBase64Alphabet[ val1 ];
            //log.debug( "val2 = " + val2 );
            //log.debug( "k4   = " + (k<<4) );
            //log.debug(  "vak  = " + (val2 | (k<<4)) );
            encodedData[encodedIndex+1] =
                lookUpBase64Alphabet[ val2 | ( k<<4 )];
            encodedData[encodedIndex+2] =
                lookUpBase64Alphabet[ (l <<2 ) | val3 ];
            encodedData[encodedIndex+3] = lookUpBase64Alphabet[ b3 & 0x3f ];
        }
        // form integral number of 6-bit groups
        dataIndex    = i*3;
        encodedIndex = i*4;
        if (fewerThan24bits == EIGHTBIT )
        {
            b1 = binaryData[dataIndex];
            k = (byte) ( b1 &0x03 );
            //log.debug("b1=" + b1);
            //log.debug("b1<<2 = " + (b1>>2) );
            byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
            encodedData[encodedIndex]     = lookUpBase64Alphabet[ val1 ];
            encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ k<<4 ];
            encodedData[encodedIndex + 2] = PAD;
            encodedData[encodedIndex + 3] = PAD;
        }
        else if (fewerThan24bits == SIXTEENBIT)
        {
            b1 = binaryData[dataIndex];
            b2 = binaryData[dataIndex +1 ];
            l = (byte) (b2 & 0x0f);
            k = (byte) (b1 & 0x03);
            byte val1 = ((b1 & SIGN) == 0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
            byte val2 = ((b2 & SIGN) == 0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
            encodedData[encodedIndex]     = lookUpBase64Alphabet[ val1 ];
            encodedData[encodedIndex + 1] =
                lookUpBase64Alphabet[ val2 | ( k<<4 )];
            encodedData[encodedIndex + 2] = lookUpBase64Alphabet[ l<<2 ];
            encodedData[encodedIndex + 3] = PAD;
        }
        return encodedData;
    }

}





Encode/decode for RFC 2045 Base64 as defined by RFC 2045, N. Freed and N. Borenstein.

    
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * This class provides encode/decode for RFC 2045 Base64 as
 * defined by RFC 2045, N. Freed and N. Borenstein.
 * RFC 2045: Multipurpose Internet Mail Extensions (MIME)
 * Part One: Format of Internet Message Bodies. Reference
 * 1996 Available at: http://www.ietf.org/rfc/rfc2045.txt
 * This class is used by XML Schema binary format validation
 *
 * This implementation does not encode/decode streaming
 * data. You need the data that you will encode/decode
 * already on a byte arrray.
 *
 * @xerces.internal 
 *
 * @author Jeffrey Rodriguez
 * @author Sandy Gao
 * @version $Id: Base64.java 446747 2006-09-15 21:46:20Z mrglavas $
 */
public final class  Base64 {
    static private final int  BASELENGTH         = 128;
    static private final int  LOOKUPLENGTH       = 64;
    static private final int  TWENTYFOURBITGROUP = 24;
    static private final int  EIGHTBIT           = 8;
    static private final int  SIXTEENBIT         = 16;
    static private final int  SIXBIT             = 6;
    static private final int  FOURBYTE           = 4;
    static private final int  SIGN               = -128;
    static private final char PAD                = "=";
    static private final boolean fDebug          = false;
    static final private byte [] base64Alphabet        = new byte[BASELENGTH];
    static final private char [] lookUpBase64Alphabet  = new char[LOOKUPLENGTH];
    static {
        for (int i = 0; i < BASELENGTH; ++i) {
            base64Alphabet[i] = -1;
        }
        for (int i = "Z"; i >= "A"; i--) {
            base64Alphabet[i] = (byte) (i-"A");
        }
        for (int i = "z"; i>= "a"; i--) {
            base64Alphabet[i] = (byte) ( i-"a" + 26);
        }
        for (int i = "9"; i >= "0"; i--) {
            base64Alphabet[i] = (byte) (i-"0" + 52);
        }
        base64Alphabet["+"]  = 62;
        base64Alphabet["/"]  = 63;
        for (int i = 0; i<=25; i++)
            lookUpBase64Alphabet[i] = (char)("A"+i);
        for (int i = 26,  j = 0; i<=51; i++, j++)
            lookUpBase64Alphabet[i] = (char)("a"+ j);
        for (int i = 52,  j = 0; i<=61; i++, j++)
            lookUpBase64Alphabet[i] = (char)("0" + j);
        lookUpBase64Alphabet[62] = (char)"+";
        lookUpBase64Alphabet[63] = (char)"/";
    }
    protected static boolean isWhiteSpace(char octect) {
        return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
    }
    protected static boolean isPad(char octect) {
        return (octect == PAD);
    }
    protected static boolean isData(char octect) {
        return (octect < BASELENGTH && base64Alphabet[octect] != -1);
    }
    protected static boolean isBase64(char octect) {
        return (isWhiteSpace(octect) || isPad(octect) || isData(octect));
    }
    /**
     * Encodes hex octects into Base64
     *
     * @param binaryData Array containing binaryData
     * @return Encoded Base64 array
     */
    public static String encode(byte[] binaryData) {
        if (binaryData == null)
            return null;
        int      lengthDataBits    = binaryData.length*EIGHTBIT;
        if (lengthDataBits == 0) {
            return "";
        }
        
        int      fewerThan24bits   = lengthDataBits%TWENTYFOURBITGROUP;
        int      numberTriplets    = lengthDataBits/TWENTYFOURBITGROUP;
        int      numberQuartet     = fewerThan24bits != 0 ? numberTriplets+1 : numberTriplets;
        char     encodedData[]     = null;
        encodedData = new char[numberQuartet*4];
        byte k=0, l=0, b1=0,b2=0,b3=0;
        int encodedIndex = 0;
        int dataIndex   = 0;
        if (fDebug) {
            System.out.println("number of triplets = " + numberTriplets );
        }
        for (int i=0; i<numberTriplets; i++) {
            b1 = binaryData[dataIndex++];
            b2 = binaryData[dataIndex++];
            b3 = binaryData[dataIndex++];
            if (fDebug) {
                System.out.println( "b1= " + b1 +", b2= " + b2 + ", b3= " + b3 );
            }
            l  = (byte)(b2 & 0x0f);
            k  = (byte)(b1 & 0x03);
            byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
            byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
            byte val3 = ((b3 & SIGN)==0)?(byte)(b3>>6):(byte)((b3)>>6^0xfc);
            if (fDebug) {
                System.out.println( "val2 = " + val2 );
                System.out.println( "k4   = " + (k<<4));
                System.out.println( "vak  = " + (val2 | (k<<4)));
            }
            encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[ (l <<2 ) | val3 ];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[ b3 & 0x3f ];
        }
        // form integral number of 6-bit groups
        if (fewerThan24bits == EIGHTBIT) {
            b1 = binaryData[dataIndex];
            k = (byte) ( b1 &0x03 );
            if (fDebug) {
                System.out.println("b1=" + b1);
                System.out.println("b1<<2 = " + (b1>>2) );
            }
            byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
            encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[ k<<4 ];
            encodedData[encodedIndex++] = PAD;
            encodedData[encodedIndex++] = PAD;
        } else if (fewerThan24bits == SIXTEENBIT) {
            b1 = binaryData[dataIndex];
            b2 = binaryData[dataIndex +1 ];
            l = ( byte ) ( b2 &0x0f );
            k = ( byte ) ( b1 &0x03 );
            byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
            byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
            encodedData[encodedIndex++] = lookUpBase64Alphabet[ val1 ];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
            encodedData[encodedIndex++] = lookUpBase64Alphabet[ l<<2 ];
            encodedData[encodedIndex++] = PAD;
        }
        return new String(encodedData);
    }
    /**
     * Decodes Base64 data into octects
     *
     * @param encoded string containing Base64 data
     * @return Array containind decoded data.
     */
    public static byte[] decode(String encoded) {
        if (encoded == null)
            return null;
        char[] base64Data = encoded.toCharArray();
        // remove white spaces
        int len = removeWhiteSpace(base64Data);
        
        if (len%FOURBYTE != 0) {
            return null;//should be divisible by four
        }
        int      numberQuadruple    = (len/FOURBYTE );
        if (numberQuadruple == 0)
            return new byte[0];
        byte     decodedData[]      = null;
        byte     b1=0,b2=0,b3=0,b4=0;
        char     d1=0,d2=0,d3=0,d4=0;
        int i = 0;
        int encodedIndex = 0;
        int dataIndex    = 0;
        decodedData      = new byte[ (numberQuadruple)*3];
        for (; i<numberQuadruple-1; i++) {
            if (!isData( (d1 = base64Data[dataIndex++]) )||
                !isData( (d2 = base64Data[dataIndex++]) )||
                !isData( (d3 = base64Data[dataIndex++]) )||
                !isData( (d4 = base64Data[dataIndex++]) ))
                return null;//if found "no data" just return null
            b1 = base64Alphabet[d1];
            b2 = base64Alphabet[d2];
            b3 = base64Alphabet[d3];
            b4 = base64Alphabet[d4];
            decodedData[encodedIndex++] = (byte)(  b1 <<2 | b2>>4 ) ;
            decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
            decodedData[encodedIndex++] = (byte)( b3<<6 | b4 );
        }
        if (!isData( (d1 = base64Data[dataIndex++]) ) ||
            !isData( (d2 = base64Data[dataIndex++]) )) {
            return null;//if found "no data" just return null
        }
        b1 = base64Alphabet[d1];
        b2 = base64Alphabet[d2];
        d3 = base64Data[dataIndex++];
        d4 = base64Data[dataIndex++];
        if (!isData( (d3 ) ) ||
            !isData( (d4 ) )) {//Check if they are PAD characters
            if (isPad( d3 ) && isPad( d4)) {               //Two PAD e.g. 3c[Pad][Pad]
                if ((b2 & 0xf) != 0)//last 4 bits should be zero
                    return null;
                byte[] tmp = new byte[ i*3 + 1 ];
                System.arraycopy( decodedData, 0, tmp, 0, i*3 );
                tmp[encodedIndex]   = (byte)(  b1 <<2 | b2>>4 ) ;
                return tmp;
            } else if (!isPad( d3) && isPad(d4)) {               //One PAD  e.g. 3cQ[Pad]
                b3 = base64Alphabet[ d3 ];
                if ((b3 & 0x3 ) != 0)//last 2 bits should be zero
                    return null;
                byte[] tmp = new byte[ i*3 + 2 ];
                System.arraycopy( decodedData, 0, tmp, 0, i*3 );
                tmp[encodedIndex++] = (byte)(  b1 <<2 | b2>>4 );
                tmp[encodedIndex]   = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
                return tmp;
            } else {
                return null;//an error  like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data
            }
        } else { //No PAD e.g 3cQl
            b3 = base64Alphabet[ d3 ];
            b4 = base64Alphabet[ d4 ];
            decodedData[encodedIndex++] = (byte)(  b1 <<2 | b2>>4 ) ;
            decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
            decodedData[encodedIndex++] = (byte)( b3<<6 | b4 );
        }
        return decodedData;
    }
    /**
     * remove WhiteSpace from MIME containing encoded Base64 data.
     * 
     * @param data  the byte array of base64 data (with WS)
     * @return      the new length
     */
    protected static int removeWhiteSpace(char[] data) {
        if (data == null)
            return 0;
        // count characters that"s not whitespace
        int newSize = 0;
        int len = data.length;
        for (int i = 0; i < len; i++) {
            if (!isWhiteSpace(data[i]))
                data[newSize++] = data[i];
        }
        return newSize;
    }
}





Encodes and decodes to and from Base64 notation.

    
/*
  * JBoss, Home of Professional Open Source
  * Copyright 2005, JBoss Inc., and individual contributors as indicated
  * by the @authors tag. See the copyright.txt in the distribution for a
  * full listing of individual contributors.
  *
  * This is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as
  * published by the Free Software Foundation; either version 2.1 of
  * the License, or (at your option) any later version.
  *
  * This software is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
  * License along with this software; if not, write to the Free
  * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  */
import java.io.IOException;

/**
 * Encodes and decodes to and from Base64 notation.
 *
 * <p>
 * Change Log:
 * </p>
 * <ul>
 *  <li>v2.1 - Cleaned up javadoc comments and unused variables and methods. Added
 *   some convenience methods for reading and writing to and from files.</li>
 *  <li>v2.0.2 - Now specifies UTF-8 encoding in places where the code fails on systems
 *   with other encodings (like EBCDIC).</li>
 *  <li>v2.0.1 - Fixed an error when decoding a single byte, that is, when the
 *   encoded data was a single byte.</li>
 *  <li>v2.0 - I got rid of methods that used booleans to set options. 
 *   Now everything is more consolidated and cleaner. The code now detects
 *   when data that"s being decoded is gzip-compressed and will decompress it
 *   automatically. Generally things are cleaner. You"ll probably have to
 *   change some method calls that you were making to support the new
 *   options format (<tt>int</tt>s that you "OR" together).</li>
 *  <li>v1.5.1 - Fixed bug when decompressing and decoding to a             
 *   byte[] using <tt>decode( String s, boolean gzipCompressed )</tt>.      
 *   Added the ability to "suspend" encoding in the Output Stream so        
 *   you can turn on and off the encoding if you need to embed base64       
 *   data in an otherwise "normal" stream (like an XML file).</li>  
 *  <li>v1.5 - Output stream pases on flush() command but doesn"t do anything itself.
 *      This helps when using GZIP streams.
 *      Added the ability to GZip-compress objects before encoding them.</li>
 *  <li>v1.4 - Added helper methods to read/write files.</li>
 *  <li>v1.3.6 - Fixed OutputStream.flush() so that "position" is reset.</li>
 *  <li>v1.3.5 - Added flag to turn on and off line breaks. Fixed bug in input stream
 *      where last buffer being read, if not completely full, was not returned.</li>
 *  <li>v1.3.4 - Fixed when "improperly padded stream" error was thrown at the wrong time.</li>
 *  <li>v1.3.3 - Fixed I/O streams which were totally messed up.</li>
 * </ul>
 *
 * <p>
 * I am placing this code in the Public Domain. Do with it as you will.
 * This software comes with no guarantees or warranties but with
 * plenty of well-wishing instead!
 * Please visit 
 * periodically to check for updates or to contribute improvements.
 * </p>
 *
 * @author Robert Harder
 * @author rob@iharder.net
 * @version 2.1
 */
public class Base64
{
   // provide logging
 
   /* ********  P U B L I C   F I E L D S  ******** */
   /** No options specified. Value is zero. */
   public final static int NO_OPTIONS = 0;
   /** Specify encoding. */
   public final static int ENCODE = 1;
   /** Specify decoding. */
   public final static int DECODE = 0;
   /** Specify that data should be gzip-compressed. */
   public final static int GZIP = 2;
   /** Don"t break lines when encoding (violates strict Base64 specification) */
   public final static int DONT_BREAK_LINES = 8;
   /* ********  P R I V A T E   F I E L D S  ******** */
   /** Maximum line length (76) of Base64 output. */
   private final static int MAX_LINE_LENGTH = 76;
   /** The equals sign (=) as a byte. */
   private final static byte EQUALS_SIGN = (byte)"=";
   /** The new line character (\n) as a byte. */
   private final static byte NEW_LINE = (byte)"\n";
   /** Preferred encoding. */
   private final static String PREFERRED_ENCODING = "UTF-8";
   /** The 64 valid Base64 values. */
   private final static byte[] ALPHABET;
   private final static byte[] _NATIVE_ALPHABET = /* May be something funny like EBCDIC */
   { (byte)"A", (byte)"B", (byte)"C", (byte)"D", (byte)"E", (byte)"F", (byte)"G", (byte)"H", (byte)"I", (byte)"J", (byte)"K", (byte)"L", (byte)"M", (byte)"N",
         (byte)"O", (byte)"P", (byte)"Q", (byte)"R", (byte)"S", (byte)"T", (byte)"U", (byte)"V", (byte)"W", (byte)"X", (byte)"Y", (byte)"Z", (byte)"a", (byte)"b",
         (byte)"c", (byte)"d", (byte)"e", (byte)"f", (byte)"g", (byte)"h", (byte)"i", (byte)"j", (byte)"k", (byte)"l", (byte)"m", (byte)"n", (byte)"o", (byte)"p",
         (byte)"q", (byte)"r", (byte)"s", (byte)"t", (byte)"u", (byte)"v", (byte)"w", (byte)"x", (byte)"y", (byte)"z", (byte)"0", (byte)"1", (byte)"2", (byte)"3",
         (byte)"4", (byte)"5", (byte)"6", (byte)"7", (byte)"8", (byte)"9", (byte)"+", (byte)"/" };
   /** Determine which ALPHABET to use. */
   static
   {
      byte[] __bytes;
      try
      {
         __bytes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".getBytes(PREFERRED_ENCODING);
      } // end try
      catch (java.io.UnsupportedEncodingException use)
      {
         __bytes = _NATIVE_ALPHABET; // Fall back to native encoding
      } // end catch
      ALPHABET = __bytes;
   } // end static
   /**
    * Translates a Base64 value to either its 6-bit reconstruction value
    * or a negative number indicating some other meaning.
    **/
   private final static byte[] DECODABET = { -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal  0 -  8
         -5, -5, // Whitespace: Tab and Linefeed
         -9, -9, // Decimal 11 - 12
         -5, // Whitespace: Carriage Return
         -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 14 - 26
         -9, -9, -9, -9, -9, // Decimal 27 - 31
         -5, // Whitespace: Space
         -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, // Decimal 33 - 42
         62, // Plus sign at decimal 43
         -9, -9, -9, // Decimal 44 - 46
         63, // Slash at decimal 47
         52, 53, 54, 55, 56, 57, 58, 59, 60, 61, // Numbers zero through nine
         -9, -9, -9, // Decimal 58 - 60
         -1, // Equals sign at decimal 61
         -9, -9, -9, // Decimal 62 - 64
         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, // Letters "A" through "N"
         14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, // Letters "O" through "Z"
         -9, -9, -9, -9, -9, -9, // Decimal 91 - 96
         26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, // Letters "a" through "m"
         39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, // Letters "n" through "z"
         -9, -9, -9, -9 // Decimal 123 - 126
   /*,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 127 - 139
    -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 140 - 152
    -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 153 - 165
    -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 166 - 178
    -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 179 - 191
    -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 192 - 204
    -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 205 - 217
    -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 218 - 230
    -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,     // Decimal 231 - 243
    -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9         // Decimal 244 - 255 */
   };
   // I think I end up not using the BAD_ENCODING indicator.
   //private final static byte BAD_ENCODING    = -9; // Indicates error in encoding
   private final static byte WHITE_SPACE_ENC = -5; // Indicates white space in encoding
   private final static byte EQUALS_SIGN_ENC = -1; // Indicates equals sign in encoding
   /** Defeats instantiation. */
   private Base64()
   {
   }
   /* ********  E N C O D I N G   M E T H O D S  ******** */
   /**
    * Encodes up to the first three bytes of array <var>threeBytes</var>
    * and returns a four-byte array in Base64 notation.
    * The actual number of significant bytes in your array is
    * given by <var>numSigBytes</var>.
    * The array <var>threeBytes</var> needs only be as big as
    * <var>numSigBytes</var>.
    * Code can reuse a byte array by passing a four-byte array as <var>b4</var>.
    *
    * @param b4 A reusable byte array to reduce array instantiation
    * @param threeBytes the array to convert
    * @param numSigBytes the number of significant bytes in your array
    * @return four byte array in Base64 notation.
    * @since 1.5.1
    */
   private static byte[] encode3to4(byte[] b4, byte[] threeBytes, int numSigBytes)
   {
      encode3to4(threeBytes, 0, numSigBytes, b4, 0);
      return b4;
   } // end encode3to4
   /**
    * Encodes up to three bytes of the array <var>source</var>
    * and writes the resulting four Base64 bytes to <var>destination</var>.
    * The source and destination arrays can be manipulated
    * anywhere along their length by specifying
    * <var>srcOffset</var> and <var>destOffset</var>.
    * This method does not check to make sure your arrays
    * are large enough to accomodate <var>srcOffset</var> + 3 for
    * the <var>source</var> array or <var>destOffset</var> + 4 for
    * the <var>destination</var> array.
    * The actual number of significant bytes in your array is
    * given by <var>numSigBytes</var>.
    *
    * @param source the array to convert
    * @param srcOffset the index where conversion begins
    * @param numSigBytes the number of significant bytes in your array
    * @param destination the array to hold the conversion
    * @param destOffset the index where output will be put
    * @return the <var>destination</var> array
    * @since 1.3
    */
   private static byte[] encode3to4(byte[] source, int srcOffset, int numSigBytes, byte[] destination, int destOffset)
   {
      //           1         2         3
      // 01234567890123456789012345678901 Bit position
      // --------000000001111111122222222 Array position from threeBytes
      // --------|    ||    ||    ||    | Six bit groups to index ALPHABET
      //          >>18  >>12  >> 6  >> 0  Right shift necessary
      //                0x3f  0x3f  0x3f  Additional AND
      // Create buffer with zero-padding if there are only one or two
      // significant bytes passed in the array.
      // We have to shift left 24 in order to flush out the 1"s that appear
      // when Java treats a value as negative that is cast from a byte to an int.
      int inBuff = (numSigBytes > 0 ? ((source[srcOffset] << 24) >>> 8) : 0) | (numSigBytes > 1 ? ((source[srcOffset + 1] << 24) >>> 16) : 0)
            | (numSigBytes > 2 ? ((source[srcOffset + 2] << 24) >>> 24) : 0);
      switch (numSigBytes)
      {
         case 3:
            destination[destOffset] = ALPHABET[(inBuff >>> 18)];
            destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
            destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
            destination[destOffset + 3] = ALPHABET[(inBuff) & 0x3f];
            return destination;
         case 2:
            destination[destOffset] = ALPHABET[(inBuff >>> 18)];
            destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
            destination[destOffset + 2] = ALPHABET[(inBuff >>> 6) & 0x3f];
            destination[destOffset + 3] = EQUALS_SIGN;
            return destination;
         case 1:
            destination[destOffset] = ALPHABET[(inBuff >>> 18)];
            destination[destOffset + 1] = ALPHABET[(inBuff >>> 12) & 0x3f];
            destination[destOffset + 2] = EQUALS_SIGN;
            destination[destOffset + 3] = EQUALS_SIGN;
            return destination;
         default:
            return destination;
      } // end switch
   } // end encode3to4
   /**
    * Serializes an object and returns the Base64-encoded
    * version of that serialized object. If the object
    * cannot be serialized or there is another error,
    * the method will return <tt>null</tt>.
    * The object is not GZip-compressed before being encoded.
    *
    * @param serializableObject The object to encode
    * @return The Base64-encoded object
    * @since 1.4
    */
   public static String encodeObject(java.io.Serializable serializableObject)
   {
      return encodeObject(serializableObject, NO_OPTIONS);
   } // end encodeObject
   /**
    * Serializes an object and returns the Base64-encoded
    * version of that serialized object. If the object
    * cannot be serialized or there is another error,
    * the method will return <tt>null</tt>.
    * <p>
    * Valid options:<pre>
    *   GZIP: gzip-compresses object before encoding it.
    *   DONT_BREAK_LINES: don"t break lines at 76 characters
    *     <i>Note: Technically, this makes your encoding non-compliant.</i>
    * </pre>
    * <p>
    * Example: <code>encodeObject( myObj, Base64.GZIP )</code> or
    * <p>
    * Example: <code>encodeObject( myObj, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
    *
    * @param serializableObject The object to encode
    * @param options Specified options
    * @return The Base64-encoded object
    * @see Base64#GZIP
    * @see Base64#DONT_BREAK_LINES
    * @since 2.0
    */
   public static String encodeObject(java.io.Serializable serializableObject, int options)
   {
      // Streams
      java.io.ByteArrayOutputStream baos = null;
      java.io.OutputStream b64os = null;
      java.io.ObjectOutputStream oos = null;
      java.util.zip.GZIPOutputStream gzos = null;
      // Isolate options
      int gzip = (options & GZIP);
      int dontBreakLines = (options & DONT_BREAK_LINES);
      try
      {
         // ObjectOutputStream -> (GZIP) -> Base64 -> ByteArrayOutputStream
         baos = new java.io.ByteArrayOutputStream();
         b64os = new Base64.OutputStream(baos, ENCODE | dontBreakLines);
         // GZip?
         if (gzip == GZIP)
         {
            gzos = new java.util.zip.GZIPOutputStream(b64os);
            oos = new java.io.ObjectOutputStream(gzos);
         } // end if: gzip
         else oos = new java.io.ObjectOutputStream(b64os);
         oos.writeObject(serializableObject);
      } // end try
      catch (java.io.IOException e)
      {
         e.printStackTrace();
         return null;
      } // end catch
      finally
      {
         try
         {
            oos.close();
         }
         catch (Exception e)
         {
         }
         try
         {
            gzos.close();
         }
         catch (Exception e)
         {
         }
         try
         {
            b64os.close();
         }
         catch (Exception e)
         {
         }
         try
         {
            baos.close();
         }
         catch (Exception e)
         {
         }
      } // end finally
      // Return value according to relevant encoding.
      try
      {
         return new String(baos.toByteArray(), PREFERRED_ENCODING);
      } // end try
      catch (java.io.UnsupportedEncodingException uue)
      {
         return new String(baos.toByteArray());
      } // end catch
   } // end encode
   /**
    * Encodes a byte array into Base64 notation.
    * Does not GZip-compress data.
    *
    * @param source The data to convert
    * @return the encode bytes
    * @since 1.4
    */
   public static String encodeBytes(byte[] source)
   {
      return encodeBytes(source, 0, source.length, NO_OPTIONS);
   } // end encodeBytes
   /**
    * Encodes a byte array into Base64 notation.
    * <p>
    * Valid options:<pre>
    *   GZIP: gzip-compresses object before encoding it.
    *   DONT_BREAK_LINES: don"t break lines at 76 characters
    *     <i>Note: Technically, this makes your encoding non-compliant.</i>
    * </pre>
    * <p>
    * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
    * <p>
    * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
    *
    *
    * @param source The data to convert
    * @param options Specified options
    * @return the encoded bytes
    * @see Base64#GZIP
    * @see Base64#DONT_BREAK_LINES
    * @since 2.0
    */
   public static String encodeBytes(byte[] source, int options)
   {
      return encodeBytes(source, 0, source.length, options);
   } // end encodeBytes
   /**
    * Encodes a byte array into Base64 notation.
    * Does not GZip-compress data.
    *
    * @param source The data to convert
    * @param off Offset in array where conversion should begin
    * @param len Length of data to convert
    * @return the text node
    * @since 1.4
    */
   public static String encodeBytes(byte[] source, int off, int len)
   {
      return encodeBytes(source, off, len, NO_OPTIONS);
   } // end encodeBytes
   /**
    * Encodes a byte array into Base64 notation.
    * <p>
    * Valid options:<pre>
    *   GZIP: gzip-compresses object before encoding it.
    *   DONT_BREAK_LINES: don"t break lines at 76 characters
    *     <i>Note: Technically, this makes your encoding non-compliant.</i>
    * </pre>
    * <p>
    * Example: <code>encodeBytes( myData, Base64.GZIP )</code> or
    * <p>
    * Example: <code>encodeBytes( myData, Base64.GZIP | Base64.DONT_BREAK_LINES )</code>
    *
    *
    * @param source The data to convert
    * @param off Offset in array where conversion should begin
    * @param len Length of data to convert
    * @param options Specified options
    * @see Base64#GZIP
    * @see Base64#DONT_BREAK_LINES
    * @return the text node
    * @since 2.0
    */
   public static String encodeBytes(byte[] source, int off, int len, int options)
   {
      // Isolate options
      int dontBreakLines = (options & DONT_BREAK_LINES);
      int gzip = (options & GZIP);
      // Compress?
      if (gzip == GZIP)
      {
         java.io.ByteArrayOutputStream baos = null;
         java.util.zip.GZIPOutputStream gzos = null;
         Base64.OutputStream b64os = null;
         try
         {
            // GZip -> Base64 -> ByteArray
            baos = new java.io.ByteArrayOutputStream();
            b64os = new Base64.OutputStream(baos, ENCODE | dontBreakLines);
            gzos = new java.util.zip.GZIPOutputStream(b64os);
            gzos.write(source, off, len);
            gzos.close();
         } // end try
         catch (java.io.IOException e)
         {
            e.printStackTrace();
            return null;
         } // end catch
         finally
         {
            try
            {
               gzos.close();
            }
            catch (Exception e)
            {
            }
            try
            {
               b64os.close();
            }
            catch (Exception e)
            {
            }
            try
            {
               baos.close();
            }
            catch (Exception e)
            {
            }
         } // end finally
         // Return value according to relevant encoding.
         try
         {
            return new String(baos.toByteArray(), PREFERRED_ENCODING);
         } // end try
         catch (java.io.UnsupportedEncodingException uue)
         {
            return new String(baos.toByteArray());
         } // end catch
      } // end if: compress
      // Else, don"t compress. Better not to use streams at all then.
      else
      {
         // Convert option to boolean in way that code likes it.
         boolean breakLines = dontBreakLines == 0;
         int len43 = len * 4 / 3;
         byte[] outBuff = new byte[(len43) // Main 4:3
               + ((len % 3) > 0 ? 4 : 0) // Account for padding
               + (breakLines ? (len43 / MAX_LINE_LENGTH) : 0)]; // New lines
         int d = 0;
         int e = 0;
         int len2 = len - 2;
         int lineLength = 0;
         for (; d < len2; d += 3, e += 4)
         {
            encode3to4(source, d + off, 3, outBuff, e);
            lineLength += 4;
            if (breakLines && lineLength == MAX_LINE_LENGTH)
            {
               outBuff[e + 4] = NEW_LINE;
               e++;
               lineLength = 0;
            } // end if: end of line
         } // en dfor: each piece of array
         if (d < len)
         {
            encode3to4(source, d + off, len - d, outBuff, e);
            e += 4;
         } // end if: some padding needed
         // Return value according to relevant encoding.
         try
         {
            return new String(outBuff, 0, e, PREFERRED_ENCODING);
         } // end try
         catch (java.io.UnsupportedEncodingException uue)
         {
            return new String(outBuff, 0, e);
         } // end catch
      } // end else: don"t compress
   } // end encodeBytes
   /* ********  D E C O D I N G   M E T H O D S  ******** */
   /**
    * Decodes four bytes from array <var>source</var>
    * and writes the resulting bytes (up to three of them)
    * to <var>destination</var>.
    * The source and destination arrays can be manipulated
    * anywhere along their length by specifying
    * <var>srcOffset</var> and <var>destOffset</var>.
    * This method does not check to make sure your arrays
    * are large enough to accomodate <var>srcOffset</var> + 4 for
    * the <var>source</var> array or <var>destOffset</var> + 3 for
    * the <var>destination</var> array.
    * This method returns the actual number of bytes that
    * were converted from the Base64 encoding.
    *
    *
    * @param source the array to convert
    * @param srcOffset the index where conversion begins
    * @param destination the array to hold the conversion
    * @param destOffset the index where output will be put
    * @return the number of decoded bytes converted
    * @since 1.3
    */
   private static int decode4to3(byte[] source, int srcOffset, byte[] destination, int destOffset)
   {
      // Example: Dk==
      if (source[srcOffset + 2] == EQUALS_SIGN)
      {
         // Two ways to do the same thing. Don"t know which way I like best.
         //int outBuff =   ( ( DECODABET[ source[ srcOffset    ] ] << 24 ) >>>  6 )
         //              | ( ( DECODABET[ source[ srcOffset + 1] ] << 24 ) >>> 12 );
         int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12);
         destination[destOffset] = (byte)(outBuff >>> 16);
         return 1;
      }
      // Example: DkL=
      else if (source[srcOffset + 3] == EQUALS_SIGN)
      {
         // Two ways to do the same thing. Don"t know which way I like best.
         //int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] << 24 ) >>>  6 )
         //              | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
         //              | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 );
         int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12)
               | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6);
         destination[destOffset] = (byte)(outBuff >>> 16);
         destination[destOffset + 1] = (byte)(outBuff >>> 8);
         return 2;
      }
      // Example: DkLE
      else
      {
         try
         {
            // Two ways to do the same thing. Don"t know which way I like best.
            //int outBuff =   ( ( DECODABET[ source[ srcOffset     ] ] << 24 ) >>>  6 )
            //              | ( ( DECODABET[ source[ srcOffset + 1 ] ] << 24 ) >>> 12 )
            //              | ( ( DECODABET[ source[ srcOffset + 2 ] ] << 24 ) >>> 18 )
            //              | ( ( DECODABET[ source[ srcOffset + 3 ] ] << 24 ) >>> 24 );
            int outBuff = ((DECODABET[source[srcOffset]] & 0xFF) << 18) | ((DECODABET[source[srcOffset + 1]] & 0xFF) << 12)
                  | ((DECODABET[source[srcOffset + 2]] & 0xFF) << 6) | ((DECODABET[source[srcOffset + 3]] & 0xFF));
            destination[destOffset] = (byte)(outBuff >> 16);
            destination[destOffset + 1] = (byte)(outBuff >> 8);
            destination[destOffset + 2] = (byte)(outBuff);
            return 3;
         }
         catch (Exception e)
         {
            System.out.println("" + source[srcOffset] + ": " + (DECODABET[source[srcOffset]]));
            System.out.println("" + source[srcOffset + 1] + ": " + (DECODABET[source[srcOffset + 1]]));
            System.out.println("" + source[srcOffset + 2] + ": " + (DECODABET[source[srcOffset + 2]]));
            System.out.println("" + source[srcOffset + 3] + ": " + (DECODABET[source[srcOffset + 3]]));
            return -1;
         } //end catch
      }
   } // end decodeToBytes
   /**
    * Very low-level access to decoding ASCII characters in
    * the form of a byte array. Does not support automatically
    * gunzipping or any other "fancy" features.
    *
    * @param source The Base64 encoded data
    * @param off    The offset of where to begin decoding
    * @param len    The length of characters to decode
    * @return decoded data
    * @since 1.3
    */
   public static byte[] decode(byte[] source, int off, int len)
   {
      int len34 = len * 3 / 4;
      byte[] outBuff = new byte[len34]; // Upper limit on size of output
      int outBuffPosn = 0;
      byte[] b4 = new byte[4];
      int b4Posn = 0;
      int i = 0;
      byte sbiCrop = 0;
      byte sbiDecode = 0;
      for (i = off; i < off + len; i++)
      {
         sbiCrop = (byte)(source[i] & 0x7f); // Only the low seven bits
         sbiDecode = DECODABET[sbiCrop];
         if (sbiDecode >= WHITE_SPACE_ENC) // White space, Equals sign or better
         {
            if (sbiDecode >= EQUALS_SIGN_ENC)
            {
               b4[b4Posn++] = sbiCrop;
               if (b4Posn > 3)
               {
                  outBuffPosn += decode4to3(b4, 0, outBuff, outBuffPosn);
                  b4Posn = 0;
                  // If that was the equals sign, break out of "for" loop
                  if (sbiCrop == EQUALS_SIGN)
                     break;
               } // end if: quartet built
            } // end if: equals sign or better
         } // end if: white space, equals sign or better
         else
         {
            throw new IllegalStateException("Bad Base64 input character at " + i + ": " + source[i] + "(decimal)");
         } // end else:
      } // each input character
      byte[] out = new byte[outBuffPosn];
      System.arraycopy(outBuff, 0, out, 0, outBuffPosn);
      return out;
   } // end decode
   /**
    * Decodes data from Base64 notation, automatically
    * detecting gzip-compressed data and decompressing it.
    *
    * @param s the string to decode
    * @return the decoded data
    * @since 1.4
    */
   public static byte[] decode(String s)
   {
      byte[] bytes;
      try
      {
         bytes = s.getBytes(PREFERRED_ENCODING);
      } // end try
      catch (java.io.UnsupportedEncodingException uee)
      {
         bytes = s.getBytes();
      } // end catch
      //</change>
      // Decode
      bytes = decode(bytes, 0, bytes.length);
      // Check to see if it"s gzip-compressed
      // GZIP Magic Two-Byte Number: 0x8b1f (35615)
      if (bytes != null && bytes.length >= 4)
      {
         int head = (bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
         if (java.util.zip.GZIPInputStream.GZIP_MAGIC == head)
         {
            java.io.ByteArrayInputStream bais = null;
            java.util.zip.GZIPInputStream gzis = null;
            java.io.ByteArrayOutputStream baos = null;
            byte[] buffer = new byte[2048];
            int length = 0;
            try
            {
               baos = new java.io.ByteArrayOutputStream();
               bais = new java.io.ByteArrayInputStream(bytes);
               gzis = new java.util.zip.GZIPInputStream(bais);
               while ((length = gzis.read(buffer)) >= 0)
               {
                  baos.write(buffer, 0, length);
               } // end while: reading input
               // No error? Get new bytes.
               bytes = baos.toByteArray();
            } // end try
            catch (java.io.IOException e)
            {
               // Just return originally-decoded bytes
            } // end catch
            finally
            {
               try
               {
                  baos.close();
               }
               catch (Exception e)
               {
               }
               try
               {
                  gzis.close();
               }
               catch (Exception e)
               {
               }
               try
               {
                  bais.close();
               }
               catch (Exception e)
               {
               }
            } // end finally
         } // end if: gzipped
      } // end if: bytes.length >= 2
      return bytes;
   } // end decode
   /**
    * Attempts to decode Base64 data and deserialize a Java
    * Object within. Returns <tt>null</tt> if there was an error.
    *
    * @param encodedObject The Base64 data to decode
    * @return The decoded and deserialized object
    * @since 1.5
    */
   public static Object decodeToObject(String encodedObject)
   {
      // Decode and gunzip if necessary
      byte[] objBytes = decode(encodedObject);
      java.io.ByteArrayInputStream bais = null;
      java.io.ObjectInputStream ois = null;
      Object obj = null;
      try
      {
         bais = new java.io.ByteArrayInputStream(objBytes);
         ois = new java.io.ObjectInputStream(bais);
         obj = ois.readObject();
      } // end try
      catch (java.io.IOException e)
      {
         e.printStackTrace();
         obj = null;
      } // end catch
      catch (java.lang.ClassNotFoundException e)
      {
         e.printStackTrace();
         obj = null;
      } // end catch
      finally
      {
         try
         {
            bais.close();
         }
         catch (Exception e)
         {
         }
         try
         {
            ois.close();
         }
         catch (Exception e)
         {
         }
      } // end finally
      return obj;
   } // end decodeObject
   /**
    * Convenience method for encoding data to a file.
    *
    * @param dataToEncode byte array of data to encode in base64 form
    * @param filename Filename for saving encoded data
    * @return <tt>true</tt> if successful, <tt>false</tt> otherwise
    *
    * @since 2.1
    */
   public static boolean encodeToFile(byte[] dataToEncode, String filename)
   {
      boolean success = false;
      Base64.OutputStream bos = null;
      try
      {
         bos = new Base64.OutputStream(new java.io.FileOutputStream(filename), Base64.ENCODE);
         bos.write(dataToEncode);
         success = true;
      } // end try
      catch (java.io.IOException e)
      {
         success = false;
      } // end catch: IOException
      finally
      {
         try
         {
            bos.close();
         }
         catch (Exception e)
         {
         }
      } // end finally
      return success;
   } // end encodeToFile
   /**
    * Convenience method for decoding data to a file.
    *
    * @param dataToDecode Base64-encoded data as a string
    * @param filename Filename for saving decoded data
    * @return <tt>true</tt> if successful, <tt>false</tt> otherwise
    *
    * @since 2.1
    */
   public static boolean decodeToFile(String dataToDecode, String filename)
   {
      boolean success = false;
      Base64.OutputStream bos = null;
      try
      {
         bos = new Base64.OutputStream(new java.io.FileOutputStream(filename), Base64.DECODE);
         bos.write(dataToDecode.getBytes(PREFERRED_ENCODING));
         success = true;
      } // end try
      catch (java.io.IOException e)
      {
         success = false;
      } // end catch: IOException
      finally
      {
         try
         {
            bos.close();
         }
         catch (Exception e)
         {
         }
      } // end finally
      return success;
   } // end decodeToFile
   /**
    * Convenience method for reading a base64-encoded
    * file and decoding it.
    *
    * @param filename Filename for reading encoded data
    * @return decoded byte array or null if unsuccessful
    *
    * @since 2.1
    */
   public static byte[] decodeFromFile(String filename)
   {
      byte[] decodedData = null;
      Base64.InputStream bis = null;
      try
      {
         // Set up some useful variables
         java.io.File file = new java.io.File(filename);
         byte[] buffer = null;
         int length = 0;
         int numBytes = 0;
         // Check for size of file
         if (file.length() > Integer.MAX_VALUE)
         {
            throw new IllegalStateException("File is too big for this convenience method (" + file.length() + " bytes).");
         } // end if: file too big for int index
         buffer = new byte[(int)file.length()];
         // Open a stream
         bis = new Base64.InputStream(new java.io.BufferedInputStream(new java.io.FileInputStream(file)), Base64.DECODE);
         // Read until done
         while ((numBytes = bis.read(buffer, length, 4096)) >= 0)
            length += numBytes;
         // Save in a variable to return
         decodedData = new byte[length];
         System.arraycopy(buffer, 0, decodedData, 0, length);
      } // end try
      catch (java.io.IOException e)
      {
         throw new IllegalStateException("Error decoding from file " + filename);
      } // end catch: IOException
      finally
      {
         try
         {
            bis.close();
         }
         catch (Exception e)
         {
         }
      } // end finally
      return decodedData;
   } // end decodeFromFile
   /**
    * Convenience method for reading a binary file
    * and base64-encoding it.
    *
    * @param filename Filename for reading binary data
    * @return base64-encoded string or null if unsuccessful
    *
    * @since 2.1
    */
   public static String encodeFromFile(String filename)
   {
      String encodedData = null;
      Base64.InputStream bis = null;
      try
      {
         // Set up some useful variables
         java.io.File file = new java.io.File(filename);
         byte[] buffer = new byte[(int)(file.length() * 1.4)];
         int length = 0;
         int numBytes = 0;
         // Open a stream
         bis = new Base64.InputStream(new java.io.BufferedInputStream(new java.io.FileInputStream(file)), Base64.ENCODE);
         // Read until done
         while ((numBytes = bis.read(buffer, length, 4096)) >= 0)
            length += numBytes;
         // Save in a variable to return
         encodedData = new String(buffer, 0, length, Base64.PREFERRED_ENCODING);
      } // end try
      catch (java.io.IOException e)
      {
         throw new IllegalStateException("Error encoding from file " + filename);
      } // end catch: IOException
      finally
      {
         try
         {
            bis.close();
         }
         catch (Exception e)
         {
         }
      } // end finally
      return encodedData;
   } // end encodeFromFile
   /* ********  I N N E R   C L A S S   I N P U T S T R E A M  ******** */
   /**
    * A {@link Base64.InputStream} will read data from another
    * <tt>java.io.InputStream</tt>, given in the constructor,
    * and encode/decode to/from Base64 notation on the fly.
    *
    * @see Base64
    * @since 1.3
    */
   public static class InputStream extends java.io.FilterInputStream
   {
      private boolean encode; // Encoding or decoding
      private int position; // Current position in the buffer
      private byte[] buffer; // Small buffer holding converted data
      private int bufferLength; // Length of buffer (3 or 4)
      private int numSigBytes; // Number of meaningful bytes in the buffer
      private int lineLength;
      private boolean breakLines; // Break lines at less than 80 characters
      /**
       * Constructs a {@link Base64.InputStream} in DECODE mode.
       *
       * @param in the <tt>java.io.InputStream</tt> from which to read data.
       * @since 1.3
       */
      public InputStream(java.io.InputStream in)
      {
         this(in, DECODE);
      } // end constructor
      /**
       * Constructs a {@link Base64.InputStream} in
       * either ENCODE or DECODE mode.
       * <p>
       * Valid options:<pre>
       *   ENCODE or DECODE: Encode or Decode as data is read.
       *   DONT_BREAK_LINES: don"t break lines at 76 characters
       *     (only meaningful when encoding)
       *     <i>Note: Technically, this makes your encoding non-compliant.</i>
       * </pre>
       * <p>
       * Example: <code>new Base64.InputStream( in, Base64.DECODE )</code>
       *
       *
       * @param in the <tt>java.io.InputStream</tt> from which to read data.
       * @param options Specified options
       * @see Base64#ENCODE
       * @see Base64#DECODE
       * @see Base64#DONT_BREAK_LINES
       * @since 2.0
       */
      public InputStream(java.io.InputStream in, int options)
      {
         super(in);
         this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
         this.encode = (options & ENCODE) == ENCODE;
         this.bufferLength = encode ? 4 : 3;
         this.buffer = new byte[bufferLength];
         this.position = -1;
         this.lineLength = 0;
      } // end constructor
      /**
       * Reads enough of the input stream to convert
       * to/from Base64 and returns the next byte.
       *
       * @return next byte
       * @since 1.3
       */
      public int read() throws java.io.IOException
      {
         // Do we need to get data?
         if (position < 0)
         {
            if (encode)
            {
               byte[] b3 = new byte[3];
               int numBinaryBytes = 0;
               for (int i = 0; i < 3; i++)
               {
                  try
                  {
                     int b = in.read();
                     // If end of stream, b is -1.
                     if (b >= 0)
                     {
                        b3[i] = (byte)b;
                        numBinaryBytes++;
                     } // end if: not end of stream
                  } // end try: read
                  catch (java.io.IOException e)
                  {
                     // Only a problem if we got no data at all.
                     if (i == 0)
                        throw e;
                  } // end catch
               } // end for: each needed input byte
               if (numBinaryBytes > 0)
               {
                  encode3to4(b3, 0, numBinaryBytes, buffer, 0);
                  position = 0;
                  numSigBytes = 4;
               } // end if: got data
               else
               {
                  return -1;
               } // end else
            } // end if: encoding
            // Else decoding
            else
            {
               byte[] b4 = new byte[4];
               int i = 0;
               for (i = 0; i < 4; i++)
               {
                  // Read four "meaningful" bytes:
                  int b = 0;
                  do
                  {
                     b = in.read();
                  }
                  while (b >= 0 && DECODABET[b & 0x7f] <= WHITE_SPACE_ENC);
                  if (b < 0)
                     break; // Reads a -1 if end of stream
                  b4[i] = (byte)b;
               } // end for: each needed input byte
               if (i == 4)
               {
                  numSigBytes = decode4to3(b4, 0, buffer, 0);
                  position = 0;
               } // end if: got four characters
               else if (i == 0)
               {
                  return -1;
               } // end else if: also padded correctly
               else
               {
                  // Must have broken out from above.
                  throw new java.io.IOException("Improperly padded Base64 input.");
               } // end
            } // end else: decode
         } // end else: get data
         // Got data?
         if (position >= 0)
         {
            // End of relevant data?
            if (/*!encode &&*/position >= numSigBytes)
               return -1;
            if (encode && breakLines && lineLength >= MAX_LINE_LENGTH)
            {
               lineLength = 0;
               return "\n";
            } // end if
            else
            {
               lineLength++; // This isn"t important when decoding
               // but throwing an extra "if" seems
               // just as wasteful.
               int b = buffer[position++];
               if (position >= bufferLength)
                  position = -1;
               return b & 0xFF; // This is how you "cast" a byte that"s
               // intended to be unsigned.
            } // end else
         } // end if: position >= 0
         // Else error
         else
         {
            // When JDK1.4 is more accepted, use an assertion here.
            throw new java.io.IOException("Error in Base64 code reading stream.");
         } // end else
      } // end read
      /**
       * Calls {@link #read()} repeatedly until the end of stream
       * is reached or <var>len</var> bytes are read.
       * Returns number of bytes read into array or -1 if
       * end of stream is encountered.
       *
       * @param dest array to hold values
       * @param off offset for array
       * @param len max number of bytes to read into array
       * @return bytes read into array or -1 if end of stream is encountered.
       * @since 1.3
       */
      public int read(byte[] dest, int off, int len) throws java.io.IOException
      {
         int i;
         int b;
         for (i = 0; i < len; i++)
         {
            b = read();
            //if( b < 0 && i == 0 )
            //    return -1;
            if (b >= 0)
               dest[off + i] = (byte)b;
            else if (i == 0)
               return -1;
            else break; // Out of "for" loop
         } // end for: each byte read
         return i;
      } // end read
   } // end inner class InputStream
   /* ********  I N N E R   C L A S S   O U T P U T S T R E A M  ******** */
   /**
    * A {@link Base64.OutputStream} will write data to another
    * <tt>java.io.OutputStream</tt>, given in the constructor,
    * and encode/decode to/from Base64 notation on the fly.
    *
    * @see Base64
    * @since 1.3
    */
   public static class OutputStream extends java.io.FilterOutputStream
   {
      private boolean encode;
      private int position;
      private byte[] buffer;
      private int bufferLength;
      private int lineLength;
      private boolean breakLines;
      private byte[] b4; // Scratch used in a few places
      private boolean suspendEncoding;
      /**
       * Constructs a {@link Base64.OutputStream} in ENCODE mode.
       *
       * @param out the <tt>java.io.OutputStream</tt> to which data will be written.
       * @since 1.3
       */
      public OutputStream(java.io.OutputStream out)
      {
         this(out, ENCODE);
      } // end constructor
      /**
       * Constructs a {@link Base64.OutputStream} in
       * either ENCODE or DECODE mode.
       * <p>
       * Valid options:<pre>
       *   ENCODE or DECODE: Encode or Decode as data is read.
       *   DONT_BREAK_LINES: don"t break lines at 76 characters
       *     (only meaningful when encoding)
       *     <i>Note: Technically, this makes your encoding non-compliant.</i>
       * </pre>
       * <p>
       * Example: <code>new Base64.OutputStream( out, Base64.ENCODE )</code>
       *
       * @param out the <tt>java.io.OutputStream</tt> to which data will be written.
       * @param options Specified options.
       * @see Base64#ENCODE
       * @see Base64#DECODE
       * @see Base64#DONT_BREAK_LINES
       * @since 1.3
       */
      public OutputStream(java.io.OutputStream out, int options)
      {
         super(out);
         this.breakLines = (options & DONT_BREAK_LINES) != DONT_BREAK_LINES;
         this.encode = (options & ENCODE) == ENCODE;
         this.bufferLength = encode ? 3 : 4;
         this.buffer = new byte[bufferLength];
         this.position = 0;
         this.lineLength = 0;
         this.suspendEncoding = false;
         this.b4 = new byte[4];
      } // end constructor
      /**
       * Writes the byte to the output stream after
       * converting to/from Base64 notation.
       * When encoding, bytes are buffered three
       * at a time before the output stream actually
       * gets a write() call.
       * When decoding, bytes are buffered four
       * at a time.
       *
       * @param theByte the byte to write
       * @since 1.3
       */
      public void write(int theByte) throws java.io.IOException
      {
         // Encoding suspended?
         if (suspendEncoding)
         {
            super.out.write(theByte);
            return;
         } // end if: supsended
         // Encode?
         if (encode)
         {
            buffer[position++] = (byte)theByte;
            if (position >= bufferLength) // Enough to encode.
            {
               out.write(encode3to4(b4, buffer, bufferLength));
               lineLength += 4;
               if (breakLines && lineLength >= MAX_LINE_LENGTH)
               {
                  out.write(NEW_LINE);
                  lineLength = 0;
               } // end if: end of line
               position = 0;
            } // end if: enough to output
         } // end if: encoding
         // Else, Decoding
         else
         {
            // Meaningful Base64 character?
            if (DECODABET[theByte & 0x7f] > WHITE_SPACE_ENC)
            {
               buffer[position++] = (byte)theByte;
               if (position >= bufferLength) // Enough to output.
               {
                  int len = Base64.decode4to3(buffer, 0, b4, 0);
                  out.write(b4, 0, len);
                  //out.write( Base64.decode4to3( buffer ) );
                  position = 0;
               } // end if: enough to output
            } // end if: meaningful base64 character
            else if (DECODABET[theByte & 0x7f] != WHITE_SPACE_ENC)
            {
               throw new java.io.IOException("Invalid character in Base64 data.");
            } // end else: not white space either
         } // end else: decoding
      } // end write
      /**
       * Calls {@link #write(int)} repeatedly until <var>len</var>
       * bytes are written.
       *
       * @param theBytes array from which to read bytes
       * @param off offset for array
       * @param len max number of bytes to read into array
       * @since 1.3
       */
      public void write(byte[] theBytes, int off, int len) throws java.io.IOException
      {
         // Encoding suspended?
         if (suspendEncoding)
         {
            super.out.write(theBytes, off, len);
            return;
         } // end if: supsended
         for (int i = 0; i < len; i++)
         {
            write(theBytes[off + i]);
         } // end for: each byte written
      } // end write
      /**
       * Method added by PHIL. [Thanks, PHIL. -Rob]
       * This pads the buffer without closing the stream.
       * @throws IOException 
       */
      public void flushBase64() throws java.io.IOException
      {
         if (position > 0)
         {
            if (encode)
            {
               out.write(encode3to4(b4, buffer, position));
               position = 0;
            } // end if: encoding
            else
            {
               throw new java.io.IOException("Base64 input not properly padded.");
            } // end else: decoding
         } // end if: buffer partially full
      } // end flush
      /**
       * Flushes and closes (I think, in the superclass) the stream.
       *
       * @since 1.3
       */
      public void close() throws java.io.IOException
      {
         // 1. Ensure that pending characters are written
         flushBase64();
         // 2. Actually close the stream
         // Base class both flushes and closes.
         super.close();
         buffer = null;
         out = null;
      } // end close
      /**
       * Suspends encoding of the stream.
       * May be helpful if you need to embed a piece of
       * base640-encoded data in a stream.
       *
       * @since 1.5.1
       * @throws IOException 
       */
      public void suspendEncoding() throws java.io.IOException
      {
         flushBase64();
         this.suspendEncoding = true;
      } // end suspendEncoding
      /**
       * Resumes encoding of the stream.
       * May be helpful if you need to embed a piece of
       * base640-encoded data in a stream.
       *
       * @since 1.5.1
       */
      public void resumeEncoding()
      {
         this.suspendEncoding = false;
      } // end resumeEncoding
   } // end inner class OutputStream
} // end class Base64





Encodes hex octects into Base64

    
/*   Copyright 2004 The Apache Software Foundation
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *  limitations under the License.
 */

import java.io.UnsupportedEncodingException;
/**
 * This class provides encode/decode for RFC 2045 Base64 as
 * defined by RFC 2045, N. Freed and N. Borenstein.
 * RFC 2045: Multipurpose Internet Mail Extensions (MIME)
 * Part One: Format of Internet Message Bodies. Reference
 * 1996 Available at: http://www.ietf.org/rfc/rfc2045.txt
 * This class is used by XML Schema binary format validation
 *
 * This implementation does not encode/decode streaming
 * data. You need the data that you will encode/decode
 * already on a byte arrray.
 * 
 * 
 * From xmlbeans
 * @author Jeffrey Rodriguez
 * @author Sandy Gao
 * @version $Id: Base64.java 111285 2004-12-08 16:54:26Z cezar $
 */
public final class  Base64 {
    static private final int  BASELENGTH         = 255;
    static private final int  LOOKUPLENGTH       = 64;
    static private final int  TWENTYFOURBITGROUP = 24;
    static private final int  EIGHTBIT           = 8;
    static private final int  SIXTEENBIT         = 16;
    //static private final int  SIXBIT             = 6;
    static private final int  FOURBYTE           = 4;
    static private final int  SIGN               = -128;
    static private final byte PAD                = ( byte ) "=";
    static private final boolean fDebug          = false;
    static private byte [] base64Alphabet        = new byte[BASELENGTH];
    static private byte [] lookUpBase64Alphabet  = new byte[LOOKUPLENGTH];
    static {
        for (int i = 0; i<BASELENGTH; i++) {
            base64Alphabet[i] = -1;
        }
        for (int i = "Z"; i >= "A"; i--) {
            base64Alphabet[i] = (byte) (i-"A");
        }
        for (int i = "z"; i>= "a"; i--) {
            base64Alphabet[i] = (byte) ( i-"a" + 26);
        }
        for (int i = "9"; i >= "0"; i--) {
            base64Alphabet[i] = (byte) (i-"0" + 52);
        }
        base64Alphabet["+"]  = 62;
        base64Alphabet["/"]  = 63;
        for (int i = 0; i<=25; i++)
            lookUpBase64Alphabet[i] = (byte) ("A"+i );
        for (int i = 26,  j = 0; i<=51; i++, j++)
            lookUpBase64Alphabet[i] = (byte) ("a"+ j );
        for (int i = 52,  j = 0; i<=61; i++, j++)
            lookUpBase64Alphabet[i] = (byte) ("0" + j );
        lookUpBase64Alphabet[62] = (byte) "+";
        lookUpBase64Alphabet[63] = (byte) "/";
    }
    protected static boolean isWhiteSpace(byte octect) {
        return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
    }
    protected static boolean isPad(byte octect) {
        return (octect == PAD);
    }
    protected static boolean isData(byte octect) {
        return (base64Alphabet[octect] != -1);
    }
    protected static boolean isBase64(byte octect) {
        return (isWhiteSpace(octect) || isPad(octect) || isData(octect));
    }
    /**
     * Encodes hex octects into Base64
     *
     * @param binaryData Array containing binaryData
     * @return Encoded Base64 array
     */
    public static byte[] encode(byte[] binaryData) {
        if (binaryData == null)
            return null;
        int      lengthDataBits    = binaryData.length*EIGHTBIT;
        int      fewerThan24bits   = lengthDataBits%TWENTYFOURBITGROUP;
        int      numberTriplets    = lengthDataBits/TWENTYFOURBITGROUP;
        byte     encodedData[]     = null;
        if (fewerThan24bits != 0) //data not divisible by 24 bit
            encodedData = new byte[ (numberTriplets + 1 )*4  ];
        else // 16 or 8 bit
            encodedData = new byte[ numberTriplets*4 ];
        byte k=0, l=0, b1=0,b2=0,b3=0;
        int encodedIndex = 0;
        int dataIndex   = 0;
        int i           = 0;
        if (fDebug) {
            System.out.println("number of triplets = " + numberTriplets );
        }
        for (i = 0; i<numberTriplets; i++) {
            dataIndex = i*3;
            b1 = binaryData[dataIndex];
            b2 = binaryData[dataIndex + 1];
            b3 = binaryData[dataIndex + 2];
            if (fDebug) {
                System.out.println( "b1= " + b1 +", b2= " + b2 + ", b3= " + b3 );
            }
            l  = (byte)(b2 & 0x0f);
            k  = (byte)(b1 & 0x03);
            encodedIndex = i*4;
            byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
            byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
            byte val3 = ((b3 & SIGN)==0)?(byte)(b3>>6):(byte)((b3)>>6^0xfc);
            encodedData[encodedIndex]   = lookUpBase64Alphabet[ val1 ];
            if (fDebug) {
                System.out.println( "val2 = " + val2 );
                System.out.println( "k4   = " + (k<<4));
                System.out.println( "vak  = " + (val2 | (k<<4)));
            }
            encodedData[encodedIndex+1] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
            encodedData[encodedIndex+2] = lookUpBase64Alphabet[ (l <<2 ) | val3 ];
            encodedData[encodedIndex+3] = lookUpBase64Alphabet[ b3 & 0x3f ];
        }
        // form integral number of 6-bit groups
        dataIndex    = i*3;
        encodedIndex = i*4;
        if (fewerThan24bits == EIGHTBIT) {
            b1 = binaryData[dataIndex];
            k = (byte) ( b1 &0x03 );
            if (fDebug) {
                System.out.println("b1=" + b1);
                System.out.println("b1<<2 = " + (b1>>2) );
            }
            byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
            encodedData[encodedIndex]     = lookUpBase64Alphabet[ val1 ];
            encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ k<<4 ];
            encodedData[encodedIndex + 2] = PAD;
            encodedData[encodedIndex + 3] = PAD;
        } else if (fewerThan24bits == SIXTEENBIT) {
            b1 = binaryData[dataIndex];
            b2 = binaryData[dataIndex +1 ];
            l = ( byte ) ( b2 &0x0f );
            k = ( byte ) ( b1 &0x03 );
            byte val1 = ((b1 & SIGN)==0)?(byte)(b1>>2):(byte)((b1)>>2^0xc0);
            byte val2 = ((b2 & SIGN)==0)?(byte)(b2>>4):(byte)((b2)>>4^0xf0);
            encodedData[encodedIndex]     = lookUpBase64Alphabet[ val1 ];
            encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ val2 | ( k<<4 )];
            encodedData[encodedIndex + 2] = lookUpBase64Alphabet[ l<<2 ];
            encodedData[encodedIndex + 3] = PAD;
        }
        return encodedData;
    }
    /**
     * Decodes Base64 data into octects
     *
     * @param base64Data Byte array containing Base64 data
     * @return Array containind decoded data.
     */
    public static byte[] decode(byte[] base64Data) {
        if (base64Data == null)
            return null;
        // remove white spaces
        base64Data = removeWhiteSpace(base64Data);
        if (base64Data.length%FOURBYTE != 0) {
            return null;//should be divisible by four
        }
        int      numberQuadruple    = (base64Data.length/FOURBYTE );
        if (numberQuadruple == 0)
            return new byte[0];
        byte     decodedData[]      = null;
        byte     b1=0,b2=0,b3=0, b4=0;//, marker0=0, marker1=0;
        byte     d1=0,d2=0,d3=0,d4=0;
        // Throw away anything not in normalizedBase64Data
        // Adjust size
        int i = 0;
        int encodedIndex = 0;
        int dataIndex    = 0;
        decodedData      = new byte[ (numberQuadruple)*3];
        for (; i<numberQuadruple-1; i++) {
            if (!isData( (d1 = base64Data[dataIndex++]) )||
                !isData( (d2 = base64Data[dataIndex++]) )||
                !isData( (d3 = base64Data[dataIndex++]) )||
                !isData( (d4 = base64Data[dataIndex++]) ))
                return null;//if found "no data" just return null
            b1 = base64Alphabet[d1];
            b2 = base64Alphabet[d2];
            b3 = base64Alphabet[d3];
            b4 = base64Alphabet[d4];
            decodedData[encodedIndex++] = (byte)(  b1 <<2 | b2>>4 ) ;
            decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
            decodedData[encodedIndex++] = (byte)( b3<<6 | b4 );
        }
        if (!isData( (d1 = base64Data[dataIndex++]) ) ||
            !isData( (d2 = base64Data[dataIndex++]) )) {
            return null;//if found "no data" just return null
        }
        b1 = base64Alphabet[d1];
        b2 = base64Alphabet[d2];
        d3 = base64Data[dataIndex++];
        d4 = base64Data[dataIndex++];
        if (!isData( (d3 ) ) ||
            !isData( (d4 ) )) {//Check if they are PAD characters
            if (isPad( d3 ) && isPad( d4)) {               //Two PAD e.g. 3c[Pad][Pad]
                if ((b2 & 0xf) != 0)//last 4 bits should be zero
                    return null;
                byte[] tmp = new byte[ i*3 + 1 ];
                System.arraycopy( decodedData, 0, tmp, 0, i*3 );
                tmp[encodedIndex]   = (byte)(  b1 <<2 | b2>>4 ) ;
                return tmp;
            } else if (!isPad( d3) && isPad(d4)) {               //One PAD  e.g. 3cQ[Pad]
                b3 = base64Alphabet[ d3 ];
                if ((b3 & 0x3 ) != 0)//last 2 bits should be zero
                    return null;
                byte[] tmp = new byte[ i*3 + 2 ];
                System.arraycopy( decodedData, 0, tmp, 0, i*3 );
                tmp[encodedIndex++] = (byte)(  b1 <<2 | b2>>4 );
                tmp[encodedIndex]   = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
                return tmp;
            } else {
                return null;//an error  like "3c[Pad]r", "3cdX", "3cXd", "3cXX" where X is non data
            }
        } else { //No PAD e.g 3cQl
            b3 = base64Alphabet[ d3 ];
            b4 = base64Alphabet[ d4 ];
            decodedData[encodedIndex++] = (byte)(  b1 <<2 | b2>>4 ) ;
            decodedData[encodedIndex++] = (byte)(((b2 & 0xf)<<4 ) |( (b3>>2) & 0xf) );
            decodedData[encodedIndex++] = (byte)( b3<<6 | b4 );
        }
        return decodedData;
    }
//    /**
//     * Decodes Base64 data into octects
//     *
//     * @param base64Data String containing Base64 data
//     * @return string containing decoded data.
//     */
//    public static String decode(String base64Data) {
//        if (base64Data == null)
//            return null;
//
//        byte[] decoded = null;
//        try {
//            decoded = decode(base64Data.getBytes("utf-8"));
//        }
//        catch(UnsupportedEncodingException e) {
//        }
//        finally {
//            return decoded == null ? null : new String(decoded);
//        }
//    }
//
//    /**
//     * Encodes octects (using utf-8) into Base64 data
//     *
//     * @param binaryData String containing Hex data
//     * @return string containing decoded data.
//     */
//    public static String encode(String binaryData) {
//        if (binaryData == null)
//            return null;
//
//        byte[] encoded = null;
//         try {
//          encoded = encode(binaryData.getBytes("utf-8"));
//        }
//        catch(UnsupportedEncodingException e) {}
//        finally {
//            return encoded == null ? null : new String(encoded);
//        }
//    }
    /**
     * remove WhiteSpace from MIME containing encoded Base64 data.
     *
     * @param data  the byte array of base64 data (with WS)
     * @return      the byte array of base64 data (without WS)
     */
    protected static byte[] removeWhiteSpace(byte[] data) {
        if (data == null)
            return null;
        // count characters that"s not whitespace
        int newSize = 0;
        int len = data.length;
        for (int i = 0; i < len; i++) {
            if (!isWhiteSpace(data[i]))
                newSize++;
        }
        // if no whitespace, just return the input array
        if (newSize == len)
            return data;
        // create the array to return
        byte[] newArray = new byte[newSize];
        int j = 0;
        for (int i = 0; i < len; i++) {
            if (!isWhiteSpace(data[i]))
                newArray[j++] = data[i];
        }
        return newArray;
    }
}





Encoding of raw bytes to base64-encoded characters, and decoding of base64 characters to raw bytes

    
//////////////////////license & copyright header/////////////////////////
//                                                                     //
//    Base64 - encode/decode data using the Base64 encoding scheme     //
//                                                                     //
//                Copyright (c) 1998 by Kevin Kelley                   //
//                                                                     //
// This library is free software; you can redistribute it and/or       //
// modify it under the terms of the GNU Lesser General Public          //
// License as published by the Free Software Foundation; either        //
// version 2.1 of the License, or (at your option) any later version.  //
//                                                                     //
// This library is distributed in the hope that it will be useful,     //
// but WITHOUT ANY WARRANTY; without even the implied warranty of      //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the       //
// GNU Lesser General Public License for more details.                 //
//                                                                     //
// You should have received a copy of the GNU Lesser General Public    //
// License along with this library; if not, write to the Free Software //
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA           //
// 02111-1307, USA, or contact the author:                             //
//                                                                     //
// Kevin Kelley <kelley@ruralnet.net> - 30718 Rd. 28, La Junta, CO,    //
// 81050  USA.                                                         //
//                                                                     //
////////////////////end license & copyright header///////////////////////

import java.io.*;       // needed only for main() method.

/**
*   Provides encoding of raw bytes to base64-encoded characters, and
*  decoding of base64 characters to raw bytes.
*
* @author Kevin Kelley (kelley@ruralnet.net)
* @version 1.3
* date 06 August 1998
* modified 14 February 2000
* modified 22 September 2000
*/
public class Base64 {
/**
* returns an array of base64-encoded characters to represent the
* passed data array.
*
* @param data the array of bytes to encode
* @return base64-coded character array.
*/
static public char[] encode(byte[] data)
{
    char[] out = new char[((data.length + 2) / 3) * 4];
    //
    // 3 bytes encode to 4 chars.  Output is always an even
    // multiple of 4 characters.
    //
    for (int i=0, index=0; i<data.length; i+=3, index+=4) {
        boolean quad = false;
        boolean trip = false;
        int val = (0xFF & (int) data[i]);
        val <<= 8;
        if ((i+1) < data.length) {
            val |= (0xFF & (int) data[i+1]);
            trip = true;
        }
        val <<= 8;
        if ((i+2) < data.length) {
            val |= (0xFF & (int) data[i+2]);
            quad = true;
        }
        out[index+3] = alphabet[(quad? (val & 0x3F): 64)];
        val >>= 6;
        out[index+2] = alphabet[(trip? (val & 0x3F): 64)];
        val >>= 6;
        out[index+1] = alphabet[val & 0x3F];
        val >>= 6;
        out[index+0] = alphabet[val & 0x3F];
    }
    return out;
}
  /**
   * Decodes a BASE-64 encoded stream to recover the original
   * data. White space before and after will be trimmed away,
   * but no other manipulation of the input will be performed.
   *
   * As of version 1.2 this method will properly handle input
   * containing junk characters (newlines and the like) rather
   * than throwing an error. It does this by pre-parsing the
   * input and generating from that a count of VALID input
   * characters.
   **/
static public byte[] decode(char[] data)
{
    // as our input could contain non-BASE64 data (newlines,
    // whitespace of any sort, whatever) we must first adjust
    // our count of USABLE data so that...
    // (a) we don"t misallocate the output array, and
    // (b) think that we miscalculated our data length
    //     just because of extraneous throw-away junk
    int tempLen = data.length;
    for( int ix=0; ix<data.length; ix++ )
    {
        if( (data[ix] > 255) || codes[ data[ix] ] < 0 )
            --tempLen;  // ignore non-valid chars and padding
    }
    // calculate required length:
    //  -- 3 bytes for every 4 valid base64 chars
    //  -- plus 2 bytes if there are 3 extra base64 chars,
    //     or plus 1 byte if there are 2 extra.
    int len = (tempLen / 4) * 3;
    if ((tempLen % 4) == 3) len += 2;
    if ((tempLen % 4) == 2) len += 1;
    byte[] out = new byte[len];

    int shift = 0;   // # of excess bits stored in accum
    int accum = 0;   // excess bits
    int index = 0;
    // we now go through the entire array (NOT using the "tempLen" value)
    for (int ix=0; ix<data.length; ix++)
    {
        int value = (data[ix]>255)? -1: codes[ data[ix] ];
        if ( value >= 0 )           // skip over non-code
        {
            accum <<= 6;            // bits shift up by 6 each time thru
            shift += 6;             // loop, with new bits being put in
            accum |= value;         // at the bottom.
            if ( shift >= 8 )       // whenever there are 8 or more shifted in,
            {
                shift -= 8;         // write them out (from the top, leaving any
                out[index++] =      // excess at the bottom for next iteration.
                    (byte) ((accum >> shift) & 0xff);
            }
        }
        // we will also have skipped processing a padding null byte ("=") here;
        // these are used ONLY for padding to an even length and do not legally
        // occur as encoded data. for this reason we can ignore the fact that
        // no index++ operation occurs in that special case: the out[] array is
        // initialized to all-zero bytes to start with and that works to our
        // advantage in this combination.
    }
    // if there is STILL something wrong we just have to throw up now!
    if( index != out.length)
    {
        throw new Error("Miscalculated data length (wrote " + index + " instead of " + out.length + ")");
    }
    return out;
}

//
// code characters for values 0..63
//
static private char[] alphabet =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
        .toCharArray();
//
// lookup table for converting base64 characters to value in range 0..63
//
static private byte[] codes = new byte[256];
static {
    for (int i=0; i<256; i++) codes[i] = -1;
    for (int i = "A"; i <= "Z"; i++) codes[i] = (byte)(     i - "A");
    for (int i = "a"; i <= "z"; i++) codes[i] = (byte)(26 + i - "a");
    for (int i = "0"; i <= "9"; i++) codes[i] = (byte)(52 + i - "0");
    codes["+"] = 62;
    codes["/"] = 63;
}


///////////////////////////////////////////////////
// remainder (main method and helper functions) is
// for testing purposes only, feel free to clip it.
///////////////////////////////////////////////////
public static void main(String[] args)
{
    boolean decode = false;
    if (args.length == 0) {
        System.out.println("usage:  java Base64 [-d[ecode]] filename");
        System.exit(0);
    }
    for (int i=0; i<args.length; i++) {
        if ("-decode".equalsIgnoreCase(args[i])) decode = true;
        else if ("-d".equalsIgnoreCase(args[i])) decode = true;
    }
    String filename = args[args.length-1];
    File file = new File(filename);
    if (!file.exists()) {
        System.out.println("Error:  file "" + filename + "" doesn"t exist!");
        System.exit(0);
    }
    if (decode)
    {
        char[] encoded = readChars(file);
        byte[] decoded = decode(encoded);
        writeBytes(file, decoded);
    }
    else
    {
        byte[] decoded = readBytes(file);
        char[] encoded = encode(decoded);
        writeChars(file, encoded);
    }
}
private static byte[] readBytes(File file)
{
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    try
    {
        InputStream fis = new FileInputStream(file);
        InputStream is = new BufferedInputStream(fis);
        int count = 0;
        byte[] buf = new byte[16384];
        while ((count=is.read(buf)) != -1) {
            if (count > 0) baos.write(buf, 0, count);
        }
        is.close();
    }
    catch (Exception e) { e.printStackTrace(); }
    return baos.toByteArray();
}
private static char[] readChars(File file)
{
    CharArrayWriter caw = new CharArrayWriter();
    try
    {
        Reader fr = new FileReader(file);
        Reader in = new BufferedReader(fr);
        int count = 0;
        char[] buf = new char[16384];
        while ((count=in.read(buf)) != -1) {
            if (count > 0) caw.write(buf, 0, count);
        }
        in.close();
    }
    catch (Exception e) { e.printStackTrace(); }
    return caw.toCharArray();
}
private static void writeBytes(File file, byte[] data) {
    try {
        OutputStream fos = new FileOutputStream(file);
        OutputStream os = new BufferedOutputStream(fos);
        os.write(data);
        os.close();
    }
    catch (Exception e) { e.printStackTrace(); }
}
private static void writeChars(File file, char[] data) {
    try {
        Writer fos = new FileWriter(file);
        Writer os = new BufferedWriter(fos);
        os.write(data);
        os.close();
    }
    catch (Exception e) { e.printStackTrace(); }
}

}





Helper class to provide Base64 encoding routines.

    
/*******************************************************************************
 * Copyright (C) 2006 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 ******************************************************************************/

/**
 * Helper class to provide Base64 encoding routines.
 * 
 * @author ? - added by ksim
 * @date March 6th, 2007
 * @version 1.0
 * @todo Not unit tested yet.
 */
/**
 * The <b>Base64Coder</b> class provides methods for encoding strings and byte
 * arrays into Base64 format. It also provides methods for decoding
 * Base64-encoded strings and character arrays.
 * 
 * @version 1.0 beta
 */
public class Base64Coder {
  private Base64Coder() {
  }
  /**
   * Mapping table from 6-bit nibbles to Base64 characters.
   */
  private static char[] map1 = new char[64];
  static {
    int i = 0;
    for (char c = "A"; c <= "Z"; c++) {
      map1[i++] = c;
    }
    for (char c = "a"; c <= "z"; c++) {
      map1[i++] = c;
    }
    for (char c = "0"; c <= "9"; c++) {
      map1[i++] = c;
    }
    map1[i++] = "+";
    map1[i++] = "/";
  }
  /**
   * Mapping table from Base64 characters to 6-bit nibbles.
   */
  private static byte[] map2 = new byte[128];
  static {
    for (int i = 0; i < map2.length; i++) {
      map2[i] = -1;
    }
    for (int i = 0; i < 64; i++) {
      map2[map1[i]] = (byte) i;
    }
  }
  /**
   * The <b>encode (String s)</b> method encodes a string into Base64 format.
   * No blanks or line breaks are inserted.
   * 
   * @param s
   *            The string to be encoded.
   * @return String in Base64-encoded format.
   */
  public static String encode(String s) {
    return new String(encode(s.getBytes()));
  }
  /**
   * The <b>encode (byte[] in)</b> method encodes a byte array into Base64
   * format. No blanks or line breaks are inserted.
   * 
   * @param in
   *            An array containing the data bytes to be encoded.
   * @return A character array containing the Base64-encoded data.
   */
  public static char[] encode(byte[] in) {
    int iLen = in.length;
    int oDataLen = (iLen * 4 + 2) / 3; // output length without padding
    int oLen = ((iLen + 2) / 3) * 4; // output length including padding
    char[] out = new char[oLen];
    int ip = 0;
    int op = 0;
    while (ip < iLen) {
      int i0 = in[ip++] & 0xff;
      int i1 = ip < iLen ? in[ip++] & 0xff : 0;
      int i2 = ip < iLen ? in[ip++] & 0xff : 0;
      int o0 = i0 >>> 2;
      int o1 = ((i0 & 3) << 4) | (i1 >>> 4);
      int o2 = ((i1 & 0xf) << 2) | (i2 >>> 6);
      int o3 = i2 & 0x3F;
      out[op++] = map1[o0];
      out[op++] = map1[o1];
      out[op] = op < oDataLen ? map1[o2] : "=";
      op++;
      out[op] = op < oDataLen ? map1[o3] : "=";
      op++;
    }
    return out;
  }
  /**
   * The <b>decode (String s)</b> method decodes a Base64-encoded string.
   * 
   * @param s
   *            The Base64 String to be decoded.
   * @return A String containing the decoded data.
   * @throws IllegalArgumentException
   *             if the input is not valid Base64-encoded data.
   */
  public static String decode(String s) {
    return new String(decode(s.toCharArray()));
  }
  /**
   * The <b>decode (char[] in)</b> method decodes an array of Base64-encoded
   * characters. No blanks or line breaks are allowed within the
   * Base64-encoded data.
   * 
   * @param in
   *            A character array containing the Base64-encoded data.
   * @return An array containing the decoded data bytes.
   * @throws IllegalArgumentException
   *             if the input is not valid Base64-encoded data.
   */
  public static byte[] decode(char[] in) {
    int iLen = in.length;
    if (iLen % 4 != 0)
      throw new IllegalArgumentException(
          "Length of Base64 encoded input "
              + "string is not a multiple of 4.");
    while (iLen > 0 && in[iLen - 1] == "=")
      iLen--;
    int oLen = (iLen * 3) / 4;
    byte[] out = new byte[oLen];
    int ip = 0;
    int op = 0;
    while (ip < iLen) {
      int i0 = in[ip++];
      int i1 = in[ip++];
      int i2 = ip < iLen ? in[ip++] : "A";
      int i3 = ip < iLen ? in[ip++] : "A";
      if (i0 > 127 || i1 > 127 || i2 > 127 || i3 > 127)
        throw new IllegalArgumentException("Illegal character in "
            + "Base64 encoded data.");
      int b0 = map2[i0];
      int b1 = map2[i1];
      int b2 = map2[i2];
      int b3 = map2[i3];
      if (b0 < 0 || b1 < 0 || b2 < 0 || b3 < 0)
        throw new IllegalArgumentException(
            "Illegal character in Base64 " + "encoded data.");
      int o0 = (b0 << 2) | (b1 >>> 4);
      int o1 = ((b1 & 0xf) << 4) | (b2 >>> 2);
      int o2 = ((b2 & 3) << 6) | b3;
      out[op++] = (byte) o0;
      if (op < oLen) {
        out[op++] = (byte) o1;
      }
      if (op < oLen) {
        out[op++] = (byte) o2;
      }
    }
    return out;
  }
}





Implementation of MIME"s Base64 encoding and decoding conversions.

    
/*
 * Copyright  1999-2004 The Apache Software Foundation.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 */
public class Base64 {
  /**
   * Implementation of MIME"s Base64 encoding and decoding conversions.
   * Optimized code. (raw version taken from oreilly.jonathan.util, and
   * currently org.apache.xerces.ds.util.Base64)
   * 
   * @author Raul Benito(Of the xerces copy, and little adaptations).
   * @author Anli Shundi
   * @author Christian Geuer-Pollmann
   * @see 
   * @see org.apache.xml.security.transforms.implementations.TransformBase64Decode
   */
  /**
   * Field BASE64DEFAULTLENGTH
   */
  public static final int BASE64DEFAULTLENGTH = 76;
  /**
   * Field _base64length
   */
  static int _base64length = Base64.BASE64DEFAULTLENGTH;
  static private final int BASELENGTH = 255;
  static private final int LOOKUPLENGTH = 64;
  static private final int TWENTYFOURBITGROUP = 24;
  static private final int EIGHTBIT = 8;
  static private final int SIXTEENBIT = 16;
  static private final int FOURBYTE = 4;
  static private final int SIGN = -128;
  static private final char PAD = "=";
  static final private byte[] base64Alphabet = new byte[BASELENGTH];
  static final private char[] lookUpBase64Alphabet = new char[LOOKUPLENGTH];
  static {
    for (int i = 0; i < BASELENGTH; i++) {
      base64Alphabet[i] = -1;
    }
    for (int i = "Z"; i >= "A"; i--) {
      base64Alphabet[i] = (byte) (i - "A");
    }
    for (int i = "z"; i >= "a"; i--) {
      base64Alphabet[i] = (byte) (i - "a" + 26);
    }
    for (int i = "9"; i >= "0"; i--) {
      base64Alphabet[i] = (byte) (i - "0" + 52);
    }
    base64Alphabet["+"] = 62;
    base64Alphabet["/"] = 63;
    for (int i = 0; i <= 25; i++)
      lookUpBase64Alphabet[i] = (char) ("A" + i);
    for (int i = 26, j = 0; i <= 51; i++, j++)
      lookUpBase64Alphabet[i] = (char) ("a" + j);
    for (int i = 52, j = 0; i <= 61; i++, j++)
      lookUpBase64Alphabet[i] = (char) ("0" + j);
    lookUpBase64Alphabet[62] = "+";
    lookUpBase64Alphabet[63] = "/";
  }
  private Base64() {
    // we don"t allow instantiation
  }
  /**
   * Encode a byte array and fold lines at the standard 76th character.
   * 
   * @param binaryData
   *          <code>byte[]<code> to be base64 encoded
   * @return the <code>String<code> with encoded data
   */
  public static String encode(byte[] binaryData) {
    return encode(binaryData, BASE64DEFAULTLENGTH, false);
  }
  protected static boolean isWhiteSpace(byte octect) {
    return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
  }
  protected static boolean isPad(byte octect) {
    return (octect == PAD);
  }
  /**
   * Encode a byte array in Base64 format and return an optionally wrapped line.
   * 
   * @param binaryData
   *          <code>byte[]</code> data to be encoded
   * @param length
   *          <code>int<code> length of wrapped lines; No wrapping if less than 4.
   * @return a <code>String</code> with encoded data
   */
  public static String encode(byte[] binaryData, int length, boolean wrap) {
    if (length < 4) {
      length = Integer.MAX_VALUE;
    }
    if (binaryData == null)
      return null;
    int lengthDataBits = binaryData.length * EIGHTBIT;
    if (lengthDataBits == 0) {
      return "";
    }
    int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
    int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
    int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets;
    int quartesPerLine = length / 4;
    int numberLines = (numberQuartet - 1) / quartesPerLine;
    char encodedData[];
    encodedData = new char[(numberQuartet * 4) + (wrap ? numberLines : 0)];
    byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
    int encodedIndex = 0;
    int dataIndex = 0;
    int tripletsDone = 0;
    for (int line = 0; line < numberLines; line++) {
      for (int quartet = 0; quartet < quartesPerLine; quartet++) {
        b1 = binaryData[dataIndex++];
        b2 = binaryData[dataIndex++];
        b3 = binaryData[dataIndex++];
        l = (byte) (b2 & 0x0f);
        k = (byte) (b1 & 0x03);
        byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
        byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
        byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
        encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
        encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
        encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
        encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
        tripletsDone++;
      }
      if (wrap) {
        encodedData[encodedIndex++] = 0xa;
      }
    }
    for (; tripletsDone < numberTriplets; tripletsDone++) {
      b1 = binaryData[dataIndex++];
      b2 = binaryData[dataIndex++];
      b3 = binaryData[dataIndex++];
      l = (byte) (b2 & 0x0f);
      k = (byte) (b1 & 0x03);
      byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
      byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
      byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
      encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
      encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
      encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
      encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
    }
    // form integral number of 6-bit groups
    if (fewerThan24bits == EIGHTBIT) {
      b1 = binaryData[dataIndex];
      k = (byte) (b1 & 0x03);
      byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
      encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
      encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
      encodedData[encodedIndex++] = PAD;
      encodedData[encodedIndex++] = PAD;
    } else if (fewerThan24bits == SIXTEENBIT) {
      b1 = binaryData[dataIndex];
      b2 = binaryData[dataIndex + 1];
      l = (byte) (b2 & 0x0f);
      k = (byte) (b1 & 0x03);
      byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
      byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
      encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
      encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
      encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
      encodedData[encodedIndex++] = PAD;
    }
    return new String(encodedData);
  }
  /**
   * Decodes Base64 data into octects
   * 
   * @param encoded
   *          String containing Base64 data
   * @return Array containing decoded data.
   */
  public static byte[] decode(String encoded) throws RuntimeException {
    byte[] base64Data = encoded.getBytes();
    // remove white spaces
    int len = removeWhiteSpace(base64Data);
    if (len % FOURBYTE != 0) {
      throw new RuntimeException("decoding.divisible.four");
      // should be divisible by four
    }
    int numberQuadruple = (len / FOURBYTE);
    if (numberQuadruple == 0)
      return new byte[0];
    byte decodedData[] = null;
    byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
    int i = 0;
    int encodedIndex = 0;
    int dataIndex = 0;
    // decodedData = new byte[ (numberQuadruple)*3];
    dataIndex = (numberQuadruple - 1) * 4;
    encodedIndex = (numberQuadruple - 1) * 3;
    // first last bits.
    b1 = base64Alphabet[base64Data[dataIndex++]];
    b2 = base64Alphabet[base64Data[dataIndex++]];
    if ((b1 == -1) || (b2 == -1)) {
      throw new RuntimeException("decoding.general");// if found "no data" just
                                                      // return null
    }
    byte d3, d4;
    b3 = base64Alphabet[d3 = base64Data[dataIndex++]];
    b4 = base64Alphabet[d4 = base64Data[dataIndex++]];
    if ((b3 == -1) || (b4 == -1)) {
      // Check if they are PAD characters
      if (isPad(d3) && isPad(d4)) { // Two PAD e.g. 3c[Pad][Pad]
        if ((b2 & 0xf) != 0)// last 4 bits should be zero
          throw new RuntimeException("decoding.general");
        decodedData = new byte[encodedIndex + 1];
        decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
      } else if (!isPad(d3) && isPad(d4)) { // One PAD e.g. 3cQ[Pad]
        if ((b3 & 0x3) != 0)// last 2 bits should be zero
          throw new RuntimeException("decoding.general");
        decodedData = new byte[encodedIndex + 2];
        decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
        decodedData[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
      } else {
        throw new RuntimeException("decoding.general");// an error like
                                                        // "3c[Pad]r", "3cdX",
                                                        // "3cXd", "3cXX" where
                                                        // X is non data
      }
    } else {
      // No PAD e.g 3cQl
      decodedData = new byte[encodedIndex + 3];
      decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
      decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
      decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
    }
    encodedIndex = 0;
    dataIndex = 0;
    // the begin
    for (i = numberQuadruple - 1; i > 0; i--) {
      b1 = base64Alphabet[base64Data[dataIndex++]];
      b2 = base64Alphabet[base64Data[dataIndex++]];
      b3 = base64Alphabet[base64Data[dataIndex++]];
      b4 = base64Alphabet[base64Data[dataIndex++]];
      if ((b1 == -1) || (b2 == -1) || (b3 == -1) || (b4 == -1)) {
        throw new RuntimeException("decoding.general");// if found "no data"
                                                        // just return null
      }
      decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
      decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
      decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
    }
    return decodedData;
  }
  /**
   * remove WhiteSpace from MIME containing encoded Base64 data.
   * 
   * @param data
   *          the byte array of base64 data (with WS)
   * @return the new length
   */
  protected static int removeWhiteSpace(byte[] data) {
    if (data == null)
      return 0;
    // count characters that"s not whitespace
    int newSize = 0;
    int len = data.length;
    for (int i = 0; i < len; i++) {
      byte dataS = data[i];
      if (!isWhiteSpace(dataS))
        data[newSize++] = dataS;
    }
    return newSize;
  }
  /**
   * @param args
   */
  public static void main(String[] args) {
    // TODO Auto-generated method stub
  }
}





One of the fastest implementation of the Base64 encoding. Jakarta and others are slower

     
// Copyright (c) 2003-2009, Jodd Team (jodd.org). All Rights Reserved.

import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
/**
 * One of the fastest implementation of the Base64 encoding.
 * Jakarta and others are slower.
 */
public class Base64 {
  private static final char[] S_BASE64CHAR = {
    "A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
    "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T",
    "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d",
    "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
    "o", "p", "q", "r", "s", "t", "u", "v", "w", "x",
    "y", "z", "0", "1", "2", "3", "4", "5", "6", "7",
    "8", "9", "+", "/"
  };
  private static final char S_BASE64PAD = "=";
  private static final byte[] S_DECODETABLE = new byte[128];
  static {
    for (int i = 0;  i < S_DECODETABLE.length;  i ++) {
      S_DECODETABLE[i] = Byte.MAX_VALUE;          // 127
    }
    for (int i = 0;  i < S_BASE64CHAR.length;  i ++)    // 0 to 63
    {
      S_DECODETABLE[S_BASE64CHAR[i]] = (byte) i;
    }
  }
  private static int decode0(char[] ibuf, byte[] obuf, int wp) {
    int outlen = 3;
    if (ibuf[3] == S_BASE64PAD) {
      outlen = 2;
    }
    if (ibuf[2] == S_BASE64PAD) {
      outlen = 1;
    }
    int b0 = S_DECODETABLE[ibuf[0]];
    int b1 = S_DECODETABLE[ibuf[1]];
    int b2 = S_DECODETABLE[ibuf[2]];
    int b3 = S_DECODETABLE[ibuf[3]];
    switch (outlen) {
      case 1:
      obuf[wp] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3);
      return 1;
      case 2:
      obuf[wp++] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3);
      obuf[wp] = (byte) (b1 << 4 & 0xf0 | b2 >> 2 & 0xf);
      return 2;
      case 3:
      obuf[wp++] = (byte) (b0 << 2 & 0xfc | b1 >> 4 & 0x3);
      obuf[wp++] = (byte) (b1 << 4 & 0xf0 | b2 >> 2 & 0xf);
      obuf[wp] = (byte) (b2 << 6 & 0xc0 | b3 & 0x3f);
      return 3;
      default:
      throw new RuntimeException("Internal Error");
    }
  }
  
  /**
   * Decode the base64 data.
   * @param data The base64 encoded data to be decoded
   * @param off The offset within the encoded data at which to start decoding
   * @param len The length of data to decode
   * @return The decoded data
   */
  public static byte[] decode(char[] data, int off, int len) {
    char[] ibuf = new char[4];
    int ibufcount = 0;
    byte[] obuf = new byte[(len >> 2) * 3 + 3];
    int obufcount = 0;
    for (int i = off;  i < off+len;  i ++) {
      char ch = data[i];
      if (ch == S_BASE64PAD || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
        ibuf[ibufcount++] = ch;
        if (ibufcount == ibuf.length) {
          ibufcount = 0;
          obufcount += decode0(ibuf, obuf, obufcount);
        }
      }
    }
    if (obufcount == obuf.length) {
      return obuf;
    }
    byte[] ret = new byte[obufcount];
    System.arraycopy(obuf, 0, ret, 0, obufcount);
    return ret;
  }
  public static final int BUF_SIZE =  256;
  /**
   * Decode the base64 data.
   * @param data The base64 encoded data to be decoded
   * @return The decoded data
   */
  public static byte[] decode(String data) {
    int ibufcount = 0;
    int slen = data.length();
    char[] ibuf = new char[slen < BUF_SIZE +3 ? slen : BUF_SIZE + 3];
    byte[] obuf = new byte[(slen >> 2) *3+3];
    int obufcount = 0;
    int blen;
  
    for (int i = 0;  i < slen;  i +=BUF_SIZE ) {
      // buffer may contain unprocessed characters from previous step
      if (i + BUF_SIZE  <= slen)  {
        data.getChars(i, i+BUF_SIZE , ibuf, ibufcount);
        blen = BUF_SIZE + ibufcount;
      } else {
        data.getChars(i, slen, ibuf, ibufcount);
        blen = slen - i+ibufcount;
      }
  
      for (int j=ibufcount; j<blen; j++) {
        char ch = ibuf[j];
        if (ch == S_BASE64PAD || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
          ibuf[ibufcount++] = ch;
          // as soon as we have 4 chars process them
          if (ibufcount == 4) {
            ibufcount = 0;
            obufcount += decode0(ibuf, obuf, obufcount);
          }
        }
      }
    }
    if (obufcount == obuf.length) {
      return obuf;
    }
    byte[] ret = new byte[obufcount];
    System.arraycopy(obuf, 0, ret, 0, obufcount);
    return ret;
  }
  /**
   * Decode the base64 data.
   * @param data The base64 encoded data to be decoded
   * @param off The offset within the encoded data at which to start decoding
   * @param len The length of data to decode
   * @param ostream The OutputStream to which the decoded data should be
   *                written
   */
  public static void decode(char[] data, int off, int len, OutputStream ostream) throws IOException {
    char[] ibuf = new char[4];
    int ibufcount = 0;
    byte[] obuf = new byte[3];
    for (int i = off;  i < off+len;  i ++) {
      char ch = data[i];
      if (ch == S_BASE64PAD || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
        ibuf[ibufcount++] = ch;
        if (ibufcount == ibuf.length) {
          ibufcount = 0;
          int obufcount = decode0(ibuf, obuf, 0);
          ostream.write(obuf, 0, obufcount);
        }
      }
    }
  }
  
  /**
   * Decode the base64 data.
   * @param data The base64 encoded data to be decoded
   * @param ostream The OutputStream to which the decoded data should be
   *                written
   */
  public static void decode(String data, OutputStream ostream) throws IOException {
    char[] ibuf = new char[BUF_SIZE + 4];
    byte[] obuf = new byte[3];
    int slen = data.length();
    int blen;
    int ibufcount = 0;
  
    for (int i = 0;  i < slen;  i +=BUF_SIZE ) {
      // buffer may contain unprocessed characters from previous step
      if (i + BUF_SIZE  <= slen)  {
        data.getChars(i, i + BUF_SIZE , ibuf, ibufcount);
        blen = BUF_SIZE+ibufcount;
      } else {
        data.getChars(i, slen, ibuf, ibufcount);
        blen = slen - i+ibufcount;
      }
  
      for (int j=ibufcount; j<blen; j++) {
        char ch = ibuf[j];
        if (ch == S_BASE64PAD || ch < S_DECODETABLE.length && S_DECODETABLE[ch] != Byte.MAX_VALUE) {
          ibuf[ibufcount++] = ch;
          
          // as sson as we have 4 chars process them
          if (ibufcount == 4) {
            ibufcount = 0;
            int obufcount = decode0(ibuf, obuf, 0);
            ostream.write(obuf, 0, obufcount);
          }
        }
      }
    }
  }
  /**
   * Returns base64 representation of specified byte array.
   * @param data The data to be encoded
   * @return The base64 encoded data
   */
  public static String encode(byte[] data) {
    return encode(data, 0, data.length);
  }
  public static String encode(String s) {
    return encode(s.getBytes(), 0, s.length());
  }
  /**
   * Returns base64 representation of specified byte array.
   * @param data The data to be encoded
   * @param off The offset within the data at which to start encoding
   * @param len The length of the data to encode
   * @return The base64 encoded data
   */
  public static String encode(byte[] data, int off, int len) {
    if (len <= 0) {
      return "";
    }
    char[] out = new char[(len / 3 << 2) +4];
    int rindex = off;
    int windex = 0;
    int rest = len;
    while (rest >= 3) {
      int i = ((data[rindex]&0xff)<<16)
        +((data[rindex+1]&0xff)<<8)
        +(data[rindex+2]&0xff);
      out[windex++] = S_BASE64CHAR[i>>18];
      out[windex++] = S_BASE64CHAR[(i>>12)&0x3f];
      out[windex++] = S_BASE64CHAR[(i>>6)&0x3f];
      out[windex++] = S_BASE64CHAR[i&0x3f];
      rindex += 3;
      rest -= 3;
    }
    if (rest == 1) {
      int i = data[rindex]&0xff;
      out[windex++] = S_BASE64CHAR[i>>2];
      out[windex++] = S_BASE64CHAR[(i<<4)&0x3f];
      out[windex++] = S_BASE64PAD;
      out[windex++] = S_BASE64PAD;
    } else if (rest == 2) {
      int i = ((data[rindex]&0xff)<<8)+(data[rindex+1]&0xff);
      out[windex++] = S_BASE64CHAR[i>>10];
      out[windex++] = S_BASE64CHAR[(i>>4)&0x3f];
      out[windex++] = S_BASE64CHAR[(i<<2)&0x3f];
      out[windex++] = S_BASE64PAD;
    }
    return new String(out, 0, windex);
  }
  /**
   * Outputs base64 representation of the specified byte array to a byte stream.
   * @param data The data to be encoded
   * @param off The offset within the data at which to start encoding
   * @param len The length of the data to encode
   * @param ostream The OutputStream to which the encoded data should be
   *                written
   */
  public static void encode(byte[] data, int off, int len, OutputStream ostream) throws IOException {
    if (len <= 0) {
      return;
    }
    byte[] out = new byte[4];
    int rindex = off;
    int rest = len;
    while (rest >= 3) {
      int i = ((data[rindex]&0xff)<<16)
        +((data[rindex+1]&0xff)<<8)
        +(data[rindex+2]&0xff);
      out[0] = (byte)S_BASE64CHAR[i>>18];
      out[1] = (byte)S_BASE64CHAR[(i>>12)&0x3f];
      out[2] = (byte)S_BASE64CHAR[(i>>6)&0x3f];
      out[3] = (byte)S_BASE64CHAR[i&0x3f];
      ostream.write(out, 0, 4);
      rindex += 3;
      rest -= 3;
    }
    if (rest == 1) {
      int i = data[rindex]&0xff;
      out[0] = (byte)S_BASE64CHAR[i>>2];
      out[1] = (byte)S_BASE64CHAR[(i<<4)&0x3f];
      out[2] = (byte)S_BASE64PAD;
      out[3] = (byte)S_BASE64PAD;
      ostream.write(out, 0, 4);
    } else if (rest == 2) {
      int i = ((data[rindex]&0xff)<<8)+(data[rindex+1]&0xff);
      out[0] = (byte)S_BASE64CHAR[i>>10];
      out[1] = (byte)S_BASE64CHAR[(i>>4)&0x3f];
      out[2] = (byte)S_BASE64CHAR[(i<<2)&0x3f];
      out[3] = (byte)S_BASE64PAD;
      ostream.write(out, 0, 4);
    }
  }
  
  /**
   * Outputs base64 representation of the specified byte array to a character stream.
   * @param data The data to be encoded
   * @param off The offset within the data at which to start encoding
   * @param len The length of the data to encode
   * @param writer The Writer to which the encoded data should be
   *               written
   */
  public static void encode(byte[] data, int off, int len, Writer writer) throws IOException {
    if (len <= 0) {
      return;
    }
    char[] out = new char[4];
    int rindex = off;
    int rest = len;
    int output = 0;
    while (rest >= 3) {
      int i = ((data[rindex]&0xff)<<16) +((data[rindex+1]&0xff)<<8) +(data[rindex+2]&0xff);
      out[0] = S_BASE64CHAR[i>>18];
      out[1] = S_BASE64CHAR[(i>>12)&0x3f];
      out[2] = S_BASE64CHAR[(i>>6)&0x3f];
      out[3] = S_BASE64CHAR[i&0x3f];
      writer.write(out, 0, 4);
      rindex += 3;
      rest -= 3;
      output += 4;
      if (output % 76 == 0) {
        writer.write("\n");
      }
    }
    if (rest == 1) {
      int i = data[rindex]&0xff;
      out[0] = S_BASE64CHAR[i>>2];
      out[1] = S_BASE64CHAR[(i<<4)&0x3f];
      out[2] = S_BASE64PAD;
      out[3] = S_BASE64PAD;
      writer.write(out, 0, 4);
    } else if (rest == 2) {
      int i = ((data[rindex]&0xff)<<8)+(data[rindex+1]&0xff);
      out[0] = S_BASE64CHAR[i>>10];
      out[1] = S_BASE64CHAR[(i>>4)&0x3f];
      out[2] = S_BASE64CHAR[(i<<2)&0x3f];
      out[3] = S_BASE64PAD;
      writer.write(out, 0, 4);
    }
  }
}





Performs Base64 encoding and/or decoding

    
/*
 * Copyright 1999,2005 The Apache Software Foundation.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.UndeclaredThrowableException;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;

/** Performs Base64 encoding and/or decoding. This is an on-the-fly decoder: Unlike,
 * for example, the commons-codec classes, it doesn"t depend on byte arrays. In
 * other words, it has an extremely low memory profile. This is well suited even
 * for very large byte streams.
 */
public class Base64 {
  /** An exception of this type is thrown, if the decoded
   * character stream contains invalid input.
   */
  public static class DecodingException extends IOException {
    private static final long serialVersionUID = 3257006574836135478L;
    DecodingException(String pMessage) { super(pMessage); }
  }
  /** An exception of this type is thrown by the {@link SAXEncoder},
   * if writing to the target handler causes a SAX exception.
   * This class is required, because the {@link IOException}
   * allows no cause until Java 1.3.
   */
  public static class SAXIOException extends IOException {
    private static final long serialVersionUID = 3258131345216451895L;
    final SAXException saxException;
    SAXIOException(SAXException e) {
      super();
      saxException = e;
    }
    /** Returns the encapsulated {@link SAXException}.
     * @return An exception, which was thrown when invoking
     * {@link ContentHandler#characters(char[], int, int)}.
     */
    public SAXException getSAXException() { return saxException; }
  }

  /** Default line separator: \n
   */
  public static final String LINE_SEPARATOR = "\n";
  /** Default size for line wrapping.
   */
  public static final int LINE_SIZE = 76;
  /**
     * This array is a lookup table that translates 6-bit positive integer
     * index values into their "Base64 Alphabet" equivalents as specified 
     * in Table 1 of RFC 2045.
     */
    private static final char intToBase64[] = {
        "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M",
        "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
        "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
        "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
        "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "+", "/"
    };
    /**
     * This array is a lookup table that translates unicode characters
     * drawn from the "Base64 Alphabet" (as specified in Table 1 of RFC 2045)
     * into their 6-bit positive integer equivalents.  Characters that
     * are not in the Base64 alphabet but fall within the bounds of the
     * array are translated to -1.
     */
    private static final byte base64ToInt[] = {
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54,
        55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,
        5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
        24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
        35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
    };
  /** An encoder is an object, which is able to encode byte array
   * in blocks of three bytes. Any such block is converted into an
   * array of four bytes.
   */
  public static abstract class Encoder {
    private int num, numBytes;
    private final char[] charBuffer;
    private int charOffset;
    private final int wrapSize;
    private final int skipChars;
    private final String sep;
    private int lineChars = 0;
    /** Creates a new instance.
     * @param pBuffer The encoders buffer. The encoder will
     * write to the buffer as long as possible. If the
     * buffer is full or the end of data is signaled, then
     * the method {@link #writeBuffer(char[], int, int)}
     * will be invoked.
     * @param pWrapSize A nonzero value indicates, that a line
     * wrap should be performed after the given number of
     * characters. The value must be a multiple of 4. Zero
     * indicates, that no line wrap should be performed.
     * @param pSep The eol sequence being used to terminate
     * a line in case of line wraps. May be null, in which
     * case the default value {@link Base64#LINE_SEPARATOR}
     * is being used.
     */
    protected Encoder(char[] pBuffer, int pWrapSize, String pSep) {
      charBuffer = pBuffer;
      sep = pSep == null ? null : Base64.LINE_SEPARATOR;
      skipChars = pWrapSize == 0 ? 4 : 4 + sep.length();
      wrapSize = skipChars == 4 ? 0 : pWrapSize;
      if (wrapSize < 0  ||  wrapSize %4 > 0) {
        throw new IllegalArgumentException("Illegal argument for wrap size: " + pWrapSize
                           + "(Expected nonnegative multiple of 4)");
      }
      if (pBuffer.length < skipChars) {
        throw new IllegalArgumentException("The buffer must contain at least " + skipChars
                           + " characters, but has " + pBuffer.length);
      }
    }
    /** Called for writing the buffer contents to the target.
     * @param pChars The buffer being written.
     * @param pOffset Offset of first character being written.
     * @param pLen Number of characters being written.
     * @throws IOException Writing to the destination failed.
     */
    protected abstract void writeBuffer(char[] pChars, int pOffset, int pLen) throws IOException;
    private void wrap() {
      for (int j = 0;  j < sep.length();  j++) {
        charBuffer[charOffset++] = sep.charAt(j);
      }
      lineChars = 0;
    }
    /** Encodes the given byte array.
     * @param pBuffer Byte array being encoded.
     * @param pOffset Offset of first byte being encoded.
     * @param pLen Number of bytes being encoded.
     * @throws IOException Invoking the {@link #writeBuffer(char[],int,int)} method
     * for writing the encoded data failed.
     */
    public void write(byte[] pBuffer, int pOffset, int pLen) throws IOException {
      for(int i = 0;  i < pLen;  i++) {
        int b = pBuffer[pOffset++];
        if (b < 0) { b += 256; }
        num = (num << 8) + b;
        if (++numBytes == 3) {
          charBuffer[charOffset++] = intToBase64[num >> 18];
          charBuffer[charOffset++] = intToBase64[(num >> 12) & 0x3f];
          charBuffer[charOffset++] = intToBase64[(num >> 6) & 0x3f];
          charBuffer[charOffset++] = intToBase64[num & 0x3f];
          if (wrapSize > 0) {
            lineChars += 4;
            if (lineChars >= wrapSize) {
              wrap();
            }
          }
          num = 0;
          numBytes = 0;
          if (charOffset + skipChars > charBuffer.length) {
            writeBuffer(charBuffer, 0, charOffset);
            charOffset = 0;
          }
        }
      }
    }
    /** Writes any currently buffered data to the destination.
     * @throws IOException Invoking the {@link #writeBuffer(char[],int,int)}
     * method for writing the encoded data failed.
     */
    public void flush() throws IOException {
      if (numBytes > 0) {
        if (numBytes == 1) {
          charBuffer[charOffset++] = intToBase64[num >> 2];
          charBuffer[charOffset++] = intToBase64[(num << 4) & 0x3f];
          charBuffer[charOffset++] = "=";
          charBuffer[charOffset++] = "=";
        } else {
          charBuffer[charOffset++] = intToBase64[num >> 10];
          charBuffer[charOffset++] = intToBase64[(num >> 4) & 0x3f];
          charBuffer[charOffset++] = intToBase64[(num << 2) & 0x3f];
          charBuffer[charOffset++] = "=";
        }
        lineChars += 4;
        num = 0;
        numBytes = 0;
      }
      if (wrapSize > 0  &&  lineChars > 0) {
        wrap();
      }
      if (charOffset > 0) {
        writeBuffer(charBuffer, 0, charOffset);
        charOffset = 0;
      }
    }
  }
  /** An {@link OutputStream}, which is writing to the given
   * {@link Encoder}.
   */
  public static class EncoderOutputStream extends OutputStream {
    private final Encoder encoder;
    /** Creates a new instance, which is creating
     * output using the given {@link Encoder}.
     * @param pEncoder The base64 encoder being used.
     */
    public EncoderOutputStream(Encoder pEncoder) {
      encoder = pEncoder;
    }
    private final byte[] oneByte = new byte[1];
    public void write(int b) throws IOException {
      oneByte[0] = (byte) b;
      encoder.write(oneByte, 0, 1);
    }
    public void write(byte[] pBuffer, int pOffset, int pLen) throws IOException {
      encoder.write(pBuffer, pOffset, pLen);
    }
    public void close() throws IOException {
      encoder.flush();
    }
  }
  /** Returns an {@link OutputStream}, that encodes its input in Base64
   * and writes it to the given {@link Writer}. If the Base64 stream
   * ends, then the output streams {@link OutputStream#close()} method
   * must be invoked. Note, that this will <em>not</em> close the
   * target {@link Writer}!
   * @param pWriter Target writer.
   * @return An output stream, encoding its input in Base64 and writing
   * the output to the writer <code>pWriter</code>.
   */
  public static OutputStream newEncoder(Writer pWriter) {
    return newEncoder(pWriter, LINE_SIZE, LINE_SEPARATOR);
  }
  /** Returns an {@link OutputStream}, that encodes its input in Base64
   * and writes it to the given {@link Writer}. If the Base64 stream
   * ends, then the output streams {@link OutputStream#close()} method
   * must be invoked. Note, that this will <em>not</em> close the
   * target {@link Writer}!
   * @param pWriter Target writer.
   * @param pLineSize Size of one line in characters, must be a multiple
   * of four. Zero indicates, that no line wrapping should occur.
   * @param pSeparator Line separator or null, in which case the default value
   * {@link #LINE_SEPARATOR} is used.
   * @return An output stream, encoding its input in Base64 and writing
   * the output to the writer <code>pWriter</code>.
   */
  public static OutputStream newEncoder(final Writer pWriter, int pLineSize, String pSeparator) {
    final Encoder encoder = new Encoder(new char[4096], pLineSize, pSeparator){
      protected void writeBuffer(char[] pBuffer, int pOffset, int pLen) throws IOException {
        pWriter.write(pBuffer, pOffset, pLen);
      }
    };
    return new EncoderOutputStream(encoder);
  }
  /** An {@link Encoder}, which is writing to a SAX content handler.
   * This is typically used for embedding a base64 stream into an
   * XML document.
   */
  public static class SAXEncoder extends Encoder {
    private final ContentHandler handler;
    /** Creates a new instance.
     * @param pBuffer The encoders buffer.
     * @param pWrapSize A nonzero value indicates, that a line
     * wrap should be performed after the given number of
     * characters. The value must be a multiple of 4. Zero
     * indicates, that no line wrap should be performed.
     * @param pSep The eol sequence being used to terminate
     * a line in case of line wraps. May be null, in which
     * case the default value {@link Base64#LINE_SEPARATOR}
     * is being used.
     * @param pHandler The target handler.
     */
    public SAXEncoder(char[] pBuffer, int pWrapSize, String pSep,
              ContentHandler pHandler) {
      super(pBuffer, pWrapSize, pSep);
      handler = pHandler;
    }
    /** Writes to the content handler.
     * @throws SAXIOException Writing to the content handler
     * caused a SAXException.
     */
    protected void writeBuffer(char[] pChars, int pOffset, int pLen) throws IOException {
      try {
        handler.characters(pChars, pOffset, pLen);
      } catch (SAXException e) {
        throw new SAXIOException(e);
      }
    }
  }
  /** Converts the given byte array into a base64 encoded character
   * array.
   * @param pBuffer The buffer being encoded.
   * @param pOffset Offset in buffer, where to begin encoding.
   * @param pLength Number of bytes being encoded.
   * @return Character array of encoded bytes.
   */
  public static String encode(byte[] pBuffer, int pOffset, int pLength) {
    return encode(pBuffer, pOffset, pLength, LINE_SIZE, LINE_SEPARATOR);
  }
  /** Converts the given byte array into a base64 encoded character
   * array.
   * @param pBuffer The buffer being encoded.
   * @param pOffset Offset in buffer, where to begin encoding.
   * @param pLength Number of bytes being encoded.
   * @param pLineSize Size of one line in characters, must be a multiple
   * of four. Zero indicates, that no line wrapping should occur.
   * @param pSeparator Line separator or null, in which case the default value
   * {@link #LINE_SEPARATOR} is used.
   * @return Character array of encoded bytes.
   */
  public static String encode(byte[] pBuffer, int pOffset, int pLength,
                int pLineSize, String pSeparator) {
    StringWriter sw = new StringWriter();
    OutputStream ostream = newEncoder(sw, pLineSize, pSeparator);
    try {
      ostream.write(pBuffer, pOffset, pLength);
      ostream.close();
    } catch (IOException e) {
      throw new UndeclaredThrowableException(e);
    }
    return sw.toString();
  }
  /** Converts the given byte array into a base64 encoded character
   * array with the line size {@link #LINE_SIZE} and the separator
   * {@link #LINE_SEPARATOR}.
   * @param pBuffer The buffer being encoded.
   * @return Character array of encoded bytes.
   */
  public static String encode(byte[] pBuffer) {
    return encode(pBuffer, 0, pBuffer.length);
  }
  /** An encoder is an object, which is able to decode char arrays
   * in blocks of four bytes. Any such block is converted into a
   * array of three bytes.
   */
  public static abstract class Decoder {
    private final byte[] byteBuffer;
    private int byteBufferOffset;
    private int num, numBytes;
    private int eofBytes;
    /** Creates a new instance.
     * @param pBufLen The decoders buffer size. The decoder will
     * store up to this number of decoded bytes before invoking
     * {@link #writeBuffer(byte[],int,int)}.
     */
    protected Decoder(int pBufLen) {
      byteBuffer = new byte[pBufLen];
    }
    /** Called for writing the decoded bytes to the destination.
     * @param pBuffer The byte array being written.
     * @param pOffset Offset of the first byte being written.
     * @param pLen Number of bytes being written.
     * @throws IOException Writing to the destination failed.
     */
    protected abstract void writeBuffer(byte[] pBuffer, int pOffset, int pLen) throws IOException;
    /** Converts the Base64 encoded character array.
     * @param pData The character array being decoded.
     * @param pOffset Offset of first character being decoded.
     * @param pLen Number of characters being decoded.
     * @throws DecodingException Decoding failed.
     * @throws IOException An invocation of the {@link #writeBuffer(byte[],int,int)}
     * method failed.
     */
    public void write(char[] pData, int pOffset, int pLen) throws IOException {
      for (int i = 0;  i < pLen;  i++) {
        char c = pData[pOffset++];
        if (Character.isWhitespace(c)) {
          continue;
        }
        if (c == "=") {
          ++eofBytes;
          num = num << 6;
          switch(++numBytes) {
            case 1:
            case 2:
              throw new DecodingException("Unexpected end of stream character (=)");
            case 3:
              // Wait for the next "="
              break;
            case 4:
              byteBuffer[byteBufferOffset++] = (byte) (num >> 16);
              if (eofBytes == 1) {
                byteBuffer[byteBufferOffset++] = (byte) (num >> 8);
              }
              writeBuffer(byteBuffer, 0, byteBufferOffset);
              byteBufferOffset = 0;
              break;
            case 5:
              throw new DecodingException("Trailing garbage detected");
            default:
              throw new IllegalStateException("Invalid value for numBytes");
          }
        } else {
          if (eofBytes > 0) {
            throw new DecodingException("Base64 characters after end of stream character (=) detected.");
          }
          int result;
          if (c >= 0  &&  c < base64ToInt.length) {
            result = base64ToInt[c];
            if (result >= 0) {
              num = (num << 6) + result;
              if (++numBytes == 4) {
                byteBuffer[byteBufferOffset++] = (byte) (num >> 16);
                byteBuffer[byteBufferOffset++] = (byte) ((num >> 8) & 0xff);
                byteBuffer[byteBufferOffset++] = (byte) (num & 0xff);
                if (byteBufferOffset + 3 > byteBuffer.length) {
                  writeBuffer(byteBuffer, 0, byteBufferOffset);
                  byteBufferOffset = 0;
                }
                num = 0;
                numBytes = 0;
              }
              continue;
            }
            }
          if (!Character.isWhitespace(c)) {
            throw new DecodingException("Invalid Base64 character: " + (int) c);
          }
        }
      }
    }
    /** Indicates, that no more data is being expected. Writes all currently
     * buffered data to the destination by invoking {@link #writeBuffer(byte[],int,int)}.
     * @throws DecodingException Decoding failed (Unexpected end of file).
     * @throws IOException An invocation of the {@link #writeBuffer(byte[],int,int)} method failed.
     */
    public void flush() throws IOException {
      if (numBytes != 0  &&  numBytes != 4) {
        throw new DecodingException("Unexpected end of file");
      }
      if (byteBufferOffset > 0) {
        writeBuffer(byteBuffer, 0, byteBufferOffset);
        byteBufferOffset = 0;
      }
    }
  }
  /** Returns a {@link Writer}, that decodes its Base64 encoded
   * input and writes it to the given {@link OutputStream}.
   * Note, that the writers {@link Writer#close()} method will
   * <em>not</em> close the output stream <code>pStream</code>!
   * @param pStream Target output stream.
   * @return An output stream, encoding its input in Base64 and writing
   * the output to the writer <code>pWriter</code>.
   */
  public Writer newDecoder(final OutputStream pStream) {
    return new Writer(){
      private final Decoder decoder = new Decoder(1024){
        protected void writeBuffer(byte[] pBytes, int pOffset, int pLen) throws IOException {
          pStream.write(pBytes, pOffset, pLen);
        }
      };
      public void close() throws IOException {
        flush();
      }
      public void flush() throws IOException {
        decoder.flush();
        pStream.flush();
      }
      public void write(char[] cbuf, int off, int len) throws IOException {
        decoder.write(cbuf, off, len);
      }
    };
  }
  /** Converts the given base64 encoded character buffer into a byte array.
   * @param pBuffer The character buffer being decoded.
   * @param pOffset Offset of first character being decoded.
   * @param pLength Number of characters being decoded.
   * @return Converted byte array
   * @throws DecodingException The input character stream contained invalid data.
   */
  public static byte[] decode(char[] pBuffer, int pOffset, int pLength) throws DecodingException {
    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    Decoder d = new Decoder(1024){
      protected void writeBuffer(byte[] pBuf, int pOff, int pLen) throws IOException {
        baos.write(pBuf, pOff, pLen);
      }
    };
    try {
      d.write(pBuffer, pOffset, pLength);
      d.flush();
    } catch (DecodingException e) {
      throw e;
    } catch (IOException e) {
      throw new UndeclaredThrowableException(e);
    }
    return baos.toByteArray();
  }
  /** Converts the given base64 encoded character buffer into a byte array.
   * @param pBuffer The character buffer being decoded.
   * @return Converted byte array
   * @throws DecodingException The input character stream contained invalid data.
   */
  public static byte[] decode(char[] pBuffer) throws DecodingException {
    return decode(pBuffer, 0, pBuffer.length);
  }
  /** Converts the given base64 encoded String into a byte array.
   * @param pBuffer The string being decoded.
   * @return Converted byte array
   * @throws DecodingException The input character stream contained invalid data.
   */
  public static byte[] decode(String pBuffer) throws DecodingException {
    return decode(pBuffer.toCharArray());
  }
}





Provides Base64 encoding and decoding as defined by RFC 2045

    
/*
 * $Id: Base64.java 460331 2006-04-18 22:03:12Z dashorst $
 * $Revision: 460331 $ $Date: 2006-04-19 00:03:12 +0200 (Wed, 19 Apr 2006) $
 *
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
/**
 * Provides Base64 encoding and decoding as defined by RFC 2045.
 * <p/>
 * This class is taken from the Apache commons-codec, and adjusted to fit the
 * Wicket framework"s needs, especially external dependencies have been removed.
 * </p>
 * <p/>
 * This class implements section <cite>6.8. Base64 Content-Transfer-Encoding</cite>
 * from RFC 2045 <cite>Multipurpose Internet Mail Extensions (MIME) Part One:
 * Format of Internet Message Bodies</cite> by Freed and Borenstein.</p>
 *
 * @author Apache Software Foundation
 * @since 1.2
 */
public class Base64
{
    /**
     * Chunk size per RFC 2045 section 6.8.
     * <p/>
     * <p>The {@value} character limit does not count the trailing CRLF, but counts
     * all other characters, including any equal signs.</p>
     *
     * @see 
     */
    static final byte[] CHUNK_SEPARATOR = "\r\n".getBytes();
    /**
     * The base length.
     */
    static final int BASELENGTH = 255;
    /**
     * Lookup length.
     */
    static final int LOOKUPLENGTH = 64;
    /**
     * Used to calculate the number of bits in a byte.
     */
    static final int EIGHTBIT = 8;
    /**
     * Used when encoding something which has fewer than 24 bits.
     */
    static final int SIXTEENBIT = 16;
    /**
     * Used to determine how many bits data contains.
     */
    static final int TWENTYFOURBITGROUP = 24;
    /**
     * Used to get the number of Quadruples.
     */
    static final int FOURBYTE = 4;
    /**
     * Used to test the sign of a byte.
     */
    static final int SIGN = -128;
    /**
     * Byte used to pad output.
     */
    static final byte PAD = (byte) "=";
    /**
     * Contains the Base64 values <code>0</code> through <code>63</code> accessed by using character encodings as
     * indices.
     * <p/>
     * For example, <code>base64Alphabet["+"]</code> returns <code>62</code>.
     * </p>
     * <p/>
     * The value of undefined encodings is <code>-1</code>.
     * </p>
     */
    private static byte[] base64Alphabet = new byte[BASELENGTH];
    /**
     * <p/>
     * Contains the Base64 encodings <code>A</code> through <code>Z</code>, followed by <code>a</code> through
     * <code>z</code>, followed by <code>0</code> through <code>9</code>, followed by <code>+</code>, and
     * <code>/</code>.
     * </p>
     * <p/>
     * This array is accessed by using character values as indices.
     * </p>
     * <p/>
     * For example, <code>lookUpBase64Alphabet[62] </code> returns <code>"+"</code>.
     * </p>
     */
    private static byte[] lookUpBase64Alphabet = new byte[LOOKUPLENGTH];
    // Populating the lookup and character arrays
    static
    {
        for (int i = 0; i < BASELENGTH; i++)
        {
            base64Alphabet[i] = (byte) -1;
        }
        for (int i = "Z"; i >= "A"; i--)
        {
            base64Alphabet[i] = (byte) (i - "A");
        }
        for (int i = "z"; i >= "a"; i--)
        {
            base64Alphabet[i] = (byte) (i - "a" + 26);
        }
        for (int i = "9"; i >= "0"; i--)
        {
            base64Alphabet[i] = (byte) (i - "0" + 52);
        }
        base64Alphabet["+"] = 62;
        base64Alphabet["/"] = 63;
        for (int i = 0; i <= 25; i++)
        {
            lookUpBase64Alphabet[i] = (byte) ("A" + i);
        }
        for (int i = 26, j = 0; i <= 51; i++, j++)
        {
            lookUpBase64Alphabet[i] = (byte) ("a" + j);
        }
        for (int i = 52, j = 0; i <= 61; i++, j++)
        {
            lookUpBase64Alphabet[i] = (byte) ("0" + j);
        }
        lookUpBase64Alphabet[62] = (byte) "+";
        lookUpBase64Alphabet[63] = (byte) "/";
    }
    /**
     * Returns whether or not the <code>octect</code> is in the base 64 alphabet.
     *
     * @param octect The value to test
     * @return <code>true</code> if the value is defined in the the base 64 alphabet, <code>false</code> otherwise.
     */
    private static boolean isBase64(byte octect)
    {
        if (octect == PAD)
        {
            return true;
        }
        else if (octect < 0 || base64Alphabet[octect] == -1)
        {
            return false;
        }
        else
        {
            return true;
        }
    }
    /**
     * Tests a given byte array to see if it contains
     * only valid characters within the Base64 alphabet.
     *
     * @param arrayOctect byte array to test
     * @return <code>true</code> if all bytes are valid characters in the Base64
     *         alphabet or if the byte array is empty; false, otherwise
     */
    public static boolean isArrayByteBase64(byte[] arrayOctect)
    {
        arrayOctect = discardWhitespace(arrayOctect);
        int length = arrayOctect.length;
        if (length == 0)
        {
            // shouldn"t a 0 length array be valid base64 data?
            // return false;
            return true;
        }
        for (int i = 0; i < length; i++)
        {
            if (!isBase64(arrayOctect[i]))
            {
                return false;
            }
        }
        return true;
    }
    /**
     * Encodes binary data using the base64 algorithm but
     * does not chunk the output.
     *
     * @param binaryData binary data to encode
     * @return Base64 characters
     */
    public static byte[] encodeBase64(byte[] binaryData)
    {
        return encodeBase64(binaryData, false);
    }
    /**
     * Encodes binary data using the base64 algorithm and chunks
     * the encoded output into 76 character blocks
     *
     * @param binaryData binary data to encode
     * @return Base64 characters chunked in 76 character blocks
     */
    public static byte[] encodeBase64Chunked(byte[] binaryData)
    {
        return encodeBase64(binaryData, true);
    }

    /**
     * Decodes an Object using the base64 algorithm.  This method
     * is provided in order to satisfy the requirements of the
     * Decoder interface, and will throw a DecoderException if the
     * supplied object is not of type byte[].
     *
     * @param pObject Object to decode
     * @return An object (of type byte[]) containing the
     *         binary data which corresponds to the byte[] supplied.
     * @throws IllegalArgumentException if the parameter supplied is not
     *                                  of type byte[]
     */
    public Object decode(Object pObject)
    {
        if (!(pObject instanceof byte[]))
        {
            throw new IllegalArgumentException("Parameter supplied to Base64 decode is not a byte[]");
        }
        return decode((byte[]) pObject);
    }
    /**
     * Decodes a byte[] containing containing
     * characters in the Base64 alphabet.
     *
     * @param pArray A byte array containing Base64 character data
     * @return a byte array containing binary data
     */
    public byte[] decode(byte[] pArray)
    {
        return decodeBase64(pArray);
    }
    /**
     * Encodes binary data using the base64 algorithm, optionally
     * chunking the output into 76 character blocks.
     *
     * @param binaryData Array containing binary data to encode.
     * @param isChunked  if <code>true</code> this encoder will chunk
     *                   the base64 output into 76 character blocks
     * @return Base64-encoded data.
     */
    public static byte[] encodeBase64(byte[] binaryData, boolean isChunked)
    {
        int lengthDataBits = binaryData.length * EIGHTBIT;
        int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
        int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
        byte encodedData[] = null;
        int encodedDataLength = 0;
        int nbrChunks = 0;
        if (fewerThan24bits != 0)
        {
            //data not divisible by 24 bit
            encodedDataLength = (numberTriplets + 1) * 4;
        }
        else
        {
            // 16 or 8 bit
            encodedDataLength = numberTriplets * 4;
        }
        // If the output is to be "chunked" into 76 character sections, 
        // for compliance with RFC 2045 MIME, then it is important to 
        // allow for extra length to account for the separator(s)
        if (isChunked)
        {
            nbrChunks =
                    (CHUNK_SEPARATOR.length == 0 ? 0 : (int) Math.ceil((float) encodedDataLength / CHUNK_SIZE));
            encodedDataLength += nbrChunks * CHUNK_SEPARATOR.length;
        }
        encodedData = new byte[encodedDataLength];
        byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
        int encodedIndex = 0;
        int dataIndex = 0;
        int i = 0;
        int nextSeparatorIndex = CHUNK_SIZE;
        int chunksSoFar = 0;
        //log.debug("number of triplets = " + numberTriplets);
        for (i = 0; i < numberTriplets; i++)
        {
            dataIndex = i * 3;
            b1 = binaryData[dataIndex];
            b2 = binaryData[dataIndex + 1];
            b3 = binaryData[dataIndex + 2];
            //log.debug("b1= " + b1 +", b2= " + b2 + ", b3= " + b3);
            l = (byte) (b2 & 0x0f);
            k = (byte) (b1 & 0x03);
            byte val1 =
                    ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
            byte val2 =
                    ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
            byte val3 =
                    ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
            encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
            //log.debug( "val2 = " + val2 );
            //log.debug( "k4   = " + (k<<4) );
            //log.debug(  "vak  = " + (val2 | (k<<4)) );
            encodedData[encodedIndex + 1] =
                    lookUpBase64Alphabet[val2 | (k << 4)];
            encodedData[encodedIndex + 2] =
                    lookUpBase64Alphabet[(l << 2) | val3];
            encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f];
            encodedIndex += 4;
            // If we are chunking, let"s put a chunk separator down.
            if (isChunked)
            {
                // this assumes that CHUNK_SIZE % 4 == 0
                if (encodedIndex == nextSeparatorIndex)
                {
                    System.arraycopy(
                            CHUNK_SEPARATOR,
                            0,
                            encodedData,
                            encodedIndex,
                            CHUNK_SEPARATOR.length);
                    chunksSoFar++;
                    nextSeparatorIndex =
                            (CHUNK_SIZE * (chunksSoFar + 1)) +
                                    (chunksSoFar * CHUNK_SEPARATOR.length);
                    encodedIndex += CHUNK_SEPARATOR.length;
                }
            }
        }
        // form integral number of 6-bit groups
        dataIndex = i * 3;
        if (fewerThan24bits == EIGHTBIT)
        {
            b1 = binaryData[dataIndex];
            k = (byte) (b1 & 0x03);
            //log.debug("b1=" + b1);
            //log.debug("b1<<2 = " + (b1>>2) );
            byte val1 =
                    ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
            encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
            encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4];
            encodedData[encodedIndex + 2] = PAD;
            encodedData[encodedIndex + 3] = PAD;
        }
        else if (fewerThan24bits == SIXTEENBIT)
        {
            b1 = binaryData[dataIndex];
            b2 = binaryData[dataIndex + 1];
            l = (byte) (b2 & 0x0f);
            k = (byte) (b1 & 0x03);
            byte val1 =
                    ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
            byte val2 =
                    ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
            encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
            encodedData[encodedIndex + 1] =
                    lookUpBase64Alphabet[val2 | (k << 4)];
            encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2];
            encodedData[encodedIndex + 3] = PAD;
        }
        if (isChunked)
        {
            // we also add a separator to the end of the final chunk.
            if (chunksSoFar < nbrChunks)
            {
                System.arraycopy(
                        CHUNK_SEPARATOR,
                        0,
                        encodedData,
                        encodedDataLength - CHUNK_SEPARATOR.length,
                        CHUNK_SEPARATOR.length);
            }
        }
        return encodedData;
    }
    /**
     * Decodes Base64 data into octects
     *
     * @param base64Data Byte array containing Base64 data
     * @return Array containing decoded data.
     */
    public static byte[] decodeBase64(byte[] base64Data)
    {
        // RFC 2045 requires that we discard ALL non-Base64 characters
        base64Data = discardNonBase64(base64Data);
        // handle the edge case, so we don"t have to worry about it later
        if (base64Data.length == 0)
        {
            return new byte[0];
        }
        int numberQuadruple = base64Data.length / FOURBYTE;
        byte decodedData[] = null;
        byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0;
        // Throw away anything not in base64Data
        int encodedIndex = 0;
        int dataIndex = 0;
        {
            // this sizes the output array properly - rlw
            int lastData = base64Data.length;
            // ignore the "=" padding
            while (base64Data[lastData - 1] == PAD)
            {
                if (--lastData == 0)
                {
                    return new byte[0];
                }
            }
            decodedData = new byte[lastData - numberQuadruple];
        }
        for (int i = 0; i < numberQuadruple; i++)
        {
            dataIndex = i * 4;
            marker0 = base64Data[dataIndex + 2];
            marker1 = base64Data[dataIndex + 3];
            b1 = base64Alphabet[base64Data[dataIndex]];
            b2 = base64Alphabet[base64Data[dataIndex + 1]];
            if (marker0 != PAD && marker1 != PAD)
            {
                //No PAD e.g 3cQl
                b3 = base64Alphabet[marker0];
                b4 = base64Alphabet[marker1];
                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
                decodedData[encodedIndex + 1] =
                        (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
                decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4);
            }
            else if (marker0 == PAD)
            {
                //Two PAD e.g. 3c[Pad][Pad]
                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
            }
            else if (marker1 == PAD)
            {
                //One PAD e.g. 3cQ[Pad]
                b3 = base64Alphabet[marker0];
                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
                decodedData[encodedIndex + 1] =
                        (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
            }
            encodedIndex += 3;
        }
        return decodedData;
    }
    /**
     * Discards any whitespace from a base-64 encoded block.
     *
     * @param data The base-64 encoded data to discard the whitespace
     *             from.
     * @return The data, less whitespace (see RFC 2045).
     */
    static byte[] discardWhitespace(byte[] data)
    {
        byte groomedData[] = new byte[data.length];
        int bytesCopied = 0;
        for (int i = 0; i < data.length; i++)
        {
            switch (data[i])
            {
                case (byte) " " :
                case (byte) "\n" :
                case (byte) "\r" :
                case (byte) "\t" :
                    break;
                default:
                    groomedData[bytesCopied++] = data[i];
            }
        }
        byte packedData[] = new byte[bytesCopied];
        System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
        return packedData;
    }
    /**
     * Discards any characters outside of the base64 alphabet, per
     * the requirements on page 25 of RFC 2045 - "Any characters
     * outside of the base64 alphabet are to be ignored in base64
     * encoded data."
     *
     * @param data The base-64 encoded data to groom
     * @return The data, less non-base64 characters (see RFC 2045).
     */
    static byte[] discardNonBase64(byte[] data)
    {
        byte groomedData[] = new byte[data.length];
        int bytesCopied = 0;
        for (int i = 0; i < data.length; i++)
        {
            if (isBase64(data[i]))
            {
                groomedData[bytesCopied++] = data[i];
            }
        }
        byte packedData[] = new byte[bytesCopied];
        System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
        return packedData;
    }
    // Implementation of the Encoder Interface
    /**
     * Encodes an Object using the base64 algorithm.  This method
     * is provided in order to satisfy the requirements of the
     * Encoder interface, and will throw an EncoderException if the
     * supplied object is not of type byte[].
     *
     * @param pObject Object to encode
     * @return An object (of type byte[]) containing the
     *         base64 encoded data which corresponds to the byte[] supplied.
     * @throws IllegalArgumentException if the parameter supplied is not
     *                                  of type byte[]
     */
    public Object encode(Object pObject)
    {
        if (!(pObject instanceof byte[]))
        {
            throw new IllegalArgumentException(
                    "Parameter supplied to Base64 encode is not a byte[]");
        }
        return encode((byte[]) pObject);
    }
    /**
     * Encodes a byte[] containing binary data, into a byte[] containing
     * characters in the Base64 alphabet.
     *
     * @param pArray a byte array containing binary data
     * @return A byte array containing only Base64 character data
     */
    public byte[] encode(byte[] pArray)
    {
        return encodeBase64(pArray, false);
    }
}





Provides Base64 encoding and decoding with URL and filename safe alphabet as defined by RFC 3548, section 4.

    
/*
 * $Id: Base64.java 5325 2006-04-10 20:56:57 +0000 (Mon, 10 Apr 2006) jdonnerstag $
 * $Revision: 5325 $ $Date: 2006-04-10 20:56:57 +0000 (Mon, 10 Apr 2006) $
 *
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

/**
 * Provides Base64 encoding and decoding with URL and filename safe alphabet
 * as defined by RFC 3548, section 4.
 * <p/>
 * This Base64 encoder is modified to meet URL requirements. The changes are:
 * "+" => "*", 
 * "/" => "-", 
 * and no padding.
 * <p/>
 * This class is taken from the Apache commons-codec, and adjusted to fit the
 * Wicket framework"s needs, especially external dependencies have been removed.
 * </p>
 * <p/>
 * This class implements section <cite>4. Base 64 Encoding with URL and Filename Safe Alphabet</cite>
 * from RFC 3548 <cite>The Base16, Base32, and Base64 Data Encodings</cite> by Simon Josefsson.</p>
 *
 * @author Apache Software Foundation
 * @author Juergen Donnerstag
 * 
 * @since 1.2
 */
public class Base64UrlSafe
{
    /**
     * The base length.
     */
    static final int BASELENGTH = 255;
    /**
     * Lookup length.
     */
    static final int LOOKUPLENGTH = 64;
    /**
     * Used to calculate the number of bits in a byte.
     */
    static final int EIGHTBIT = 8;
    /**
     * Used when encoding something which has fewer than 24 bits.
     */
    static final int SIXTEENBIT = 16;
    /**
     * Used to determine how many bits data contains.
     */
    static final int TWENTYFOURBITGROUP = 24;
    /**
     * Used to get the number of Quadruples.
     */
    static final int FOURBYTE = 4;
    /**
     * Used to test the sign of a byte.
     */
    static final int SIGN = -128;
    /**
     * Contains the Base64 values <code>0</code> through <code>63</code> accessed by using character encodings as
     * indices.
     * <p/>
     * For example, <code>base64Alphabet["+"]</code> returns <code>62</code>.
     * </p>
     * <p/>
     * The value of undefined encodings is <code>-1</code>.
     * </p>
     */
    private static byte[] base64Alphabet = new byte[BASELENGTH];
    /**
     * <p/>
     * Contains the Base64 encodings <code>A</code> through <code>Z</code>, followed by <code>a</code> through
     * <code>z</code>, followed by <code>0</code> through <code>9</code>, followed by <code>+</code>, and
     * <code>/</code>.
     * </p>
     * <p/>
     * This array is accessed by using character values as indices.
     * </p>
     * <p/>
     * For example, <code>lookUpBase64Alphabet[62] </code> returns <code>"+"</code>.
     * </p>
     */
    private static byte[] lookUpBase64Alphabet = new byte[LOOKUPLENGTH];
    // Populating the lookup and character arrays
    static
    {
        for (int i = 0; i < BASELENGTH; i++)
        {
            base64Alphabet[i] = (byte) -1;
        }
        for (int i = "Z"; i >= "A"; i--)
        {
            base64Alphabet[i] = (byte) (i - "A");
        }
        for (int i = "z"; i >= "a"; i--)
        {
            base64Alphabet[i] = (byte) (i - "a" + 26);
        }
        for (int i = "9"; i >= "0"; i--)
        {
            base64Alphabet[i] = (byte) (i - "0" + 52);
        }
        base64Alphabet["*"] = 62;
        base64Alphabet["-"] = 63;
        for (int i = 0; i <= 25; i++)
        {
            lookUpBase64Alphabet[i] = (byte) ("A" + i);
        }
        for (int i = 26, j = 0; i <= 51; i++, j++)
        {
            lookUpBase64Alphabet[i] = (byte) ("a" + j);
        }
        for (int i = 52, j = 0; i <= 61; i++, j++)
        {
            lookUpBase64Alphabet[i] = (byte) ("0" + j);
        }
        lookUpBase64Alphabet[62] = (byte) "*";
        lookUpBase64Alphabet[63] = (byte) "-";
    }
    /**
     * Returns whether or not the <code>octect</code> is in the base 64 alphabet.
     *
     * @param octect The value to test
     * @return <code>true</code> if the value is defined in the the base 64 alphabet, <code>false</code> otherwise.
     */
    private static boolean isBase64(byte octect)
    {
        if (octect < 0 || base64Alphabet[octect] == -1)
        {
            return false;
        }
        else
        {
            return true;
        }
    }
    /**
     * Tests a given byte array to see if it contains
     * only valid characters within the Base64 alphabet.
     *
     * @param arrayOctect byte array to test
     * @return <code>true</code> if all bytes are valid characters in the Base64
     *         alphabet or if the byte array is empty; false, otherwise
     */
    public static boolean isArrayByteBase64(byte[] arrayOctect)
    {
        arrayOctect = discardWhitespace(arrayOctect);
        int length = arrayOctect.length;
        if (length == 0)
        {
            // shouldn"t a 0 length array be valid base64 data?
            // return false;
            return true;
        }
        for (int i = 0; i < length; i++)
        {
            if (!isBase64(arrayOctect[i]))
            {
                return false;
            }
        }
        return true;
    }
    /**
     * Decodes an Object using the base64 algorithm.  This method
     * is provided in order to satisfy the requirements of the
     * Decoder interface, and will throw a DecoderException if the
     * supplied object is not of type byte[].
     *
     * @param pObject Object to decode
     * @return An object (of type byte[]) containing the
     *         binary data which corresponds to the byte[] supplied.
     * @throws IllegalArgumentException if the parameter supplied is not
     *                                  of type byte[]
     */
    public Object decode(Object pObject)
    {
        if (!(pObject instanceof byte[]))
        {
            throw new IllegalArgumentException("Parameter supplied to Base64 decode is not a byte[]");
        }
        return decode((byte[]) pObject);
    }
    /**
     * Decodes a byte[] containing containing
     * characters in the Base64 alphabet.
     *
     * @param pArray A byte array containing Base64 character data
     * @return a byte array containing binary data
     */
    public byte[] decode(byte[] pArray)
    {
        return decodeBase64(pArray);
    }
    /**
     * Encodes binary data using the base64 algorithm.
     *
     * @param binaryData Array containing binary data to encode.
     * @return Base64-encoded data.
     */
    public static byte[] encodeBase64(byte[] binaryData)
    {
        int lengthDataBits = binaryData.length * EIGHTBIT;
        int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
        int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
        byte encodedData[] = null;
        int encodedDataLength = 0;
        if (fewerThan24bits != 0)
        {
            //data not divisible by 24 bit
            encodedDataLength = (numberTriplets + 1) * 4;
        }
        else
        {
            // 16 or 8 bit
            encodedDataLength = numberTriplets * 4;
        }
        if (fewerThan24bits == EIGHTBIT)
        {
          encodedDataLength -= 2;
        }
        else if (fewerThan24bits == SIXTEENBIT)
        {
          encodedDataLength -= 1;
        }
        encodedData = new byte[encodedDataLength];
        byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
        int encodedIndex = 0;
        int dataIndex = 0;
        int i = 0;
        //log.debug("number of triplets = " + numberTriplets);
        for (i = 0; i < numberTriplets; i++)
        {
            dataIndex = i * 3;
            b1 = binaryData[dataIndex];
            b2 = binaryData[dataIndex + 1];
            b3 = binaryData[dataIndex + 2];
            //log.debug("b1= " + b1 +", b2= " + b2 + ", b3= " + b3);
            l = (byte) (b2 & 0x0f);
            k = (byte) (b1 & 0x03);
            byte val1 =
                    ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
            byte val2 =
                    ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
            byte val3 =
                    ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
            encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
            //log.debug( "val2 = " + val2 );
            //log.debug( "k4   = " + (k<<4) );
            //log.debug(  "vak  = " + (val2 | (k<<4)) );
            encodedData[encodedIndex + 1] =
                    lookUpBase64Alphabet[val2 | (k << 4)];
            encodedData[encodedIndex + 2] =
                    lookUpBase64Alphabet[(l << 2) | val3];
            encodedData[encodedIndex + 3] = lookUpBase64Alphabet[b3 & 0x3f];
            encodedIndex += 4;
        }
        // form integral number of 6-bit groups
        dataIndex = i * 3;
        if (fewerThan24bits == EIGHTBIT)
        {
            b1 = binaryData[dataIndex];
            k = (byte) (b1 & 0x03);
            //log.debug("b1=" + b1);
            //log.debug("b1<<2 = " + (b1>>2) );
            byte val1 =
                    ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
            encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
            encodedData[encodedIndex + 1] = lookUpBase64Alphabet[k << 4];
        }
        else if (fewerThan24bits == SIXTEENBIT)
        {
            b1 = binaryData[dataIndex];
            b2 = binaryData[dataIndex + 1];
            l = (byte) (b2 & 0x0f);
            k = (byte) (b1 & 0x03);
            byte val1 =
                    ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
            byte val2 =
                    ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
            encodedData[encodedIndex] = lookUpBase64Alphabet[val1];
            encodedData[encodedIndex + 1] =
                    lookUpBase64Alphabet[val2 | (k << 4)];
            encodedData[encodedIndex + 2] = lookUpBase64Alphabet[l << 2];
        }
        return encodedData;
    }
    /**
     * Decodes Base64 data into octects
     *
     * @param base64Data Byte array containing Base64 data
     * @return Array containing decoded data.
     */
    public static byte[] decodeBase64(byte[] base64Data)
    {
        // RFC 2045 requires that we discard ALL non-Base64 characters
        base64Data = discardNonBase64(base64Data);
        // handle the edge case, so we don"t have to worry about it later
        if (base64Data.length == 0)
        {
            return new byte[0];
        }
        int numberQuadruple = (base64Data.length + 3) / FOURBYTE;
        byte decodedData[] = new byte[base64Data.length - numberQuadruple];
        byte b1 = 0, b2 = 0, b3 = 0, b4 = 0, marker0 = 0, marker1 = 0;
        // Throw away anything not in base64Data
        int encodedIndex = 0;
        int dataIndex = 0;
        for (int i = 0; i < numberQuadruple; i++)
        {
            dataIndex = i * 4;
            b1 = base64Alphabet[base64Data[dataIndex]];
            b2 = base64Alphabet[base64Data[dataIndex + 1]];
            if ((dataIndex + 3) < base64Data.length)
            {
                //No PAD e.g 3cQl
                b3 = base64Alphabet[base64Data[dataIndex + 2]];
                b4 = base64Alphabet[base64Data[dataIndex + 3]];
                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
                decodedData[encodedIndex + 1] =
                        (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
                decodedData[encodedIndex + 2] = (byte) (b3 << 6 | b4);
            }
            else if ((dataIndex + 2) < base64Data.length)
            {
                //One PAD e.g. 3cQ[Pad]
                b3 = base64Alphabet[base64Data[dataIndex + 2]];
                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
                decodedData[encodedIndex + 1] =
                        (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
            }
            else if ((dataIndex + 1) < base64Data.length)
            {
                //Two PAD e.g. 3c[Pad][Pad]
                decodedData[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
            }
            encodedIndex += 3;
        }
        return decodedData;
    }
    /**
     * Discards any whitespace from a base-64 encoded block.
     *
     * @param data The base-64 encoded data to discard the whitespace
     *             from.
     * @return The data, less whitespace (see RFC 2045).
     */
    static byte[] discardWhitespace(byte[] data)
    {
        byte groomedData[] = new byte[data.length];
        int bytesCopied = 0;
        for (int i = 0; i < data.length; i++)
        {
            switch (data[i])
            {
                case (byte) " " :
                case (byte) "\n" :
                case (byte) "\r" :
                case (byte) "\t" :
                    break;
                default:
                    groomedData[bytesCopied++] = data[i];
            }
        }
        byte packedData[] = new byte[bytesCopied];
        System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
        return packedData;
    }
    /**
     * Discards any characters outside of the base64 alphabet, per
     * the requirements on page 25 of RFC 2045 - "Any characters
     * outside of the base64 alphabet are to be ignored in base64
     * encoded data."
     *
     * @param data The base-64 encoded data to groom
     * @return The data, less non-base64 characters (see RFC 2045).
     */
    static byte[] discardNonBase64(byte[] data)
    {
        byte groomedData[] = new byte[data.length];
        int bytesCopied = 0;
        for (int i = 0; i < data.length; i++)
        {
            if (isBase64(data[i]))
            {
                groomedData[bytesCopied++] = data[i];
            }
        }
        byte packedData[] = new byte[bytesCopied];
        System.arraycopy(groomedData, 0, packedData, 0, bytesCopied);
        return packedData;
    }
    // Implementation of the Encoder Interface
    /**
     * Encodes an Object using the base64 algorithm.  This method
     * is provided in order to satisfy the requirements of the
     * Encoder interface, and will throw an EncoderException if the
     * supplied object is not of type byte[].
     *
     * @param pObject Object to encode
     * @return An object (of type byte[]) containing the
     *         base64 encoded data which corresponds to the byte[] supplied.
     * @throws IllegalArgumentException if the parameter supplied is not
     *                                  of type byte[]
     */
    public Object encode(Object pObject)
    {
        if (!(pObject instanceof byte[]))
        {
            throw new IllegalArgumentException(
                    "Parameter supplied to Base64 encode is not a byte[]");
        }
        return encode((byte[]) pObject);
    }
    /**
     * Encodes a byte[] containing binary data, into a byte[] containing
     * characters in the Base64 alphabet.
     *
     * @param pArray a byte array containing binary data
     * @return A byte array containing only Base64 character data
     */
    public byte[] encode(byte[] pArray)
    {
        return encodeBase64(pArray);
    }
}





Provides utility methods to Base64 encode data

    
/* 
 *
 * 
 * Copyright 2005 Vincent Massol.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * 
 * 
 */
import java.io.ByteArrayOutputStream;
/**
 * Provides utility methods to Base64 encode data. This class uses the Base64 encoding as specified
 * in RFC 2045, 6.8. Base64 Content-Transfer-Encoding.
 * 
 * @version $Id: Base64.java 1705 2008-09-02 13:14:55Z adriana $
 */
public final class Base64
{
    // constants --------------------------------------------------------------
    /**
     * The Base64 character set look-up table. This consists of the following ordered alphanumerics:
     * A-Z, a-z, 0-9, + and /.
     */
    private static final char[] ENCODE = new char[64];
    /**
     * The character to pad the output with if not a multiple of 24-bits.
     */
    private static final char PAD_CHAR = "=";
    // static -----------------------------------------------------------------
    static
    {
        // create Base64 character look-up table
        for (int i = 0; i < 26; i++)
        {
            ENCODE[i] = (char) ("A" + i);
            ENCODE[i + 26] = (char) ("a" + i);
        }
        for (int i = 0; i < 10; i++)
        {
            ENCODE[i + 52] = (char) ("0" + i);
        }
        ENCODE[62] = "+";
        ENCODE[63] = "/";
    }
    // constructors -----------------------------------------------------------
    /**
     * Private to prevent unnecessary instantation.
     */
    private Base64()
    {
        // Private to prevent unnecessary instantation
    }
    // public methods ---------------------------------------------------------
    /**
     * Base64 encodes the specified bytes. This method is provided for signature compatibility with
     * commons-codec.
     * 
     * @param bytes the bytes to encode
     * @return the encoded bytes
     */
    public static byte[] encodeBase64(byte[] bytes)
    {
        return encode(bytes);
    }
    /**
     * Base64 encodes the specified string using the platform"s default encoding.
     * 
     * @param string the string to encode
     * @return the encoded string
     */
    public static String encode(String string)
    {
        return new String(encode(string.getBytes()));
    }
    /**
     * Base64 encodes the specified bytes.
     * 
     * @param bytes the bytes to encode
     * @return the encoded bytes
     */
    public static byte[] encode(byte[] bytes)
    {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int count = 0;
        int carry = 0;
        for (int i = 0; i < bytes.length; i++)
        {
            byte b = bytes[i];
            switch (count++ % 3)
            {
                // first byte of 24-bits: write 6-bits and carry 2-bits
                case 0:
                    out.write(ENCODE[b >> 2]);
                    carry = b & 0x03;
                    break;
                // second byte of 24-bits: write carry + 4-bits, carry 4-bits
                case 1:
                    out.write(ENCODE[(carry << 4) + (b >> 4)]);
                    carry = b & 0x0F;
                    break;
                // third byte of 24-bits: write carry + 2-bits, write 6-bits
                case 2:
                    out.write(ENCODE[(carry << 2) + (b >> 6)]);
                    out.write(ENCODE[b & 0x3F]);
                    break;
                default:
                    throw new InternalError();
            }
        }
        switch (count % 3)
        {
            // third byte of 24-bits: 24-bit aligned
            case 0:
                break;
            // first byte of 24-bits: write 4-bit carry and pad 16-bits
            case 1:
                out.write(ENCODE[carry << 4]);
                out.write(PAD_CHAR);
                out.write(PAD_CHAR);
                break;
            // second byte of 24-bits: write 2-bit carry and pad 8-bits
            case 2:
                out.write(ENCODE[carry << 2]);
                out.write(PAD_CHAR);
                break;
            default:
                throw new InternalError();
        }
        return out.toByteArray();
    }
}





QP Decoder Stream

    
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 *
 * Contributor(s):
 *
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don"t indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
/*
 * @(#)QPDecoderStream.java 1.11 07/05/04
 */

import java.io.*;
/**
 * This class implements a QP Decoder. It is implemented as
 * a FilterInputStream, so one can just wrap this class around
 * any input stream and read bytes from this filter. The decoding
 * is done as the bytes are read out.
 * 
 * @author John Mani
 */
public class QPDecoderStream extends FilterInputStream {
    protected byte[] ba = new byte[2];
    protected int spaces = 0;
    /**
     * Create a Quoted Printable decoder that decodes the specified 
     * input stream.
     * @param in        the input stream
     */
    public QPDecoderStream(InputStream in) {
  super(new PushbackInputStream(in, 2)); // pushback of size=2
    }
    /**
     * Read the next decoded byte from this input stream. The byte
     * is returned as an <code>int</code> in the range <code>0</code>
     * to <code>255</code>. If no byte is available because the end of
     * the stream has been reached, the value <code>-1</code> is returned.
     * This method blocks until input data is available, the end of the
     * stream is detected, or an exception is thrown.
     *
     * @return     the next byte of data, or <code>-1</code> if the end of the
     *             stream is reached.
     * @exception  IOException  if an I/O error occurs.
     */
    public int read() throws IOException {
  if (spaces > 0) {
      // We have cached space characters, return one
      spaces--;
      return " ";
  }
  
  int c = in.read();
  if (c == " ") { 
      // Got space, keep reading till we get a non-space char
      while ((c = in.read()) == " ")
    spaces++;
      if (c == "\r" || c == "\n" || c == -1)
    // If the non-space char is CR/LF/EOF, the spaces we got
        // so far is junk introduced during transport. Junk "em.
    spaces = 0;
          else {
    // The non-space char is NOT CR/LF, the spaces are valid.
    ((PushbackInputStream)in).unread(c);
    c = " ";
      }
      return c; // return either <SPACE> or <CR/LF>
  }
  else if (c == "=") {
      // QP Encoded atom. Decode the next two bytes
      int a = in.read();
      if (a == "\n") {
    /* Hmm ... not really confirming QP encoding, but lets
     * allow this as a LF terminated encoded line .. and
     * consider this a soft linebreak and recurse to fetch 
     * the next char.
     */
    return read();
      } else if (a == "\r") {
    // Expecting LF. This forms a soft linebreak to be ignored.
    int b = in.read();
    if (b != "\n") 
        /* Not really confirming QP encoding, but
         * lets allow this as well.
         */
        ((PushbackInputStream)in).unread(b);
    return read();
      } else if (a == -1) {
      // Not valid QP encoding, but we be nice and tolerant here !
    return -1;
      } else {
    ba[0] = (byte)a;
    ba[1] = (byte)in.read();
    try {
        return ASCIIUtility.parseInt(ba, 0, 2, 16);
    } catch (NumberFormatException nex) {
        /*
        System.err.println(
          "Illegal characters in QP encoded stream: " + 
          ASCIIUtility.toString(ba, 0, 2)
        );
        */
        ((PushbackInputStream)in).unread(ba);
        return c;
    }
      }
  }
  return c;
    }
    /**
     * Reads up to <code>len</code> decoded bytes of data from this input stream
     * into an array of bytes. This method blocks until some input is
     * available.
     * <p>
     *
     * @param      buf   the buffer into which the data is read.
     * @param      off   the start offset of the data.
     * @param      len   the maximum number of bytes read.
     * @return     the total number of bytes read into the buffer, or
     *             <code>-1</code> if there is no more data because the end of
     *             the stream has been reached.
     * @exception  IOException  if an I/O error occurs.
     */
    public int read(byte[] buf, int off, int len) throws IOException {
  int i, c;
  for (i = 0; i < len; i++) {
      if ((c = read()) == -1) {
    if (i == 0) // At end of stream, so we should
        i = -1; // return -1 , NOT 0.
    break;
      }
      buf[off+i] = (byte)c;
  }
        return i;
    }
    /**
     * Tests if this input stream supports marks. Currently this class
     * does not support marks
     */
    public boolean markSupported() {
  return false;
    }
    /**
     * Returns the number of bytes that can be read from this input
     * stream without blocking. The QP algorithm does not permit
     * a priori knowledge of the number of bytes after decoding, so
     * this method just invokes the <code>available</code> method
     * of the original input stream.
     */
    public int available() throws IOException {
  // This is bogus ! We don"t really know how much
  // bytes are available *after* decoding
  return in.available();
    }
    /**** begin TEST program
    public static void main(String argv[]) throws Exception {
        FileInputStream infile = new FileInputStream(argv[0]);
        QPDecoderStream decoder = new QPDecoderStream(infile);
        int c;
 
        while ((c = decoder.read()) != -1)
            System.out.print((char)c);
        System.out.println();
    }
    *** end TEST program ****/
}
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 *
 * Contributor(s):
 *
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don"t indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
/*
 * @(#)ASCIIUtility.java  1.11 07/05/04
 */
 class ASCIIUtility {
    // Private constructor so that this class is not instantiated
    private ASCIIUtility() { }
  
    /**
     * Convert the bytes within the specified range of the given byte 
     * array into a signed integer in the given radix . The range extends 
     * from <code>start</code> till, but not including <code>end</code>. <p>
     *
     * Based on java.lang.Integer.parseInt()
     */
    public static int parseInt(byte[] b, int start, int end, int radix)
    throws NumberFormatException {
  if (b == null)
      throw new NumberFormatException("null");
  
  int result = 0;
  boolean negative = false;
  int i = start;
  int limit;
  int multmin;
  int digit;
  if (end > start) {
      if (b[i] == "-") {
    negative = true;
    limit = Integer.MIN_VALUE;
    i++;
      } else {
    limit = -Integer.MAX_VALUE;
      }
      multmin = limit / radix;
      if (i < end) {
    digit = Character.digit((char)b[i++], radix);
    if (digit < 0) {
        throw new NumberFormatException(
      "illegal number: " + toString(b, start, end)
      );
    } else {
        result = -digit;
    }
      }
      while (i < end) {
    // Accumulating negatively avoids surprises near MAX_VALUE
    digit = Character.digit((char)b[i++], radix);
    if (digit < 0) {
        throw new NumberFormatException("illegal number");
    }
    if (result < multmin) {
        throw new NumberFormatException("illegal number");
    }
    result *= radix;
    if (result < limit + digit) {
        throw new NumberFormatException("illegal number");
    }
    result -= digit;
      }
  } else {
      throw new NumberFormatException("illegal number");
  }
  if (negative) {
      if (i > start + 1) {
    return result;
      } else {  /* Only got "-" */
    throw new NumberFormatException("illegal number");
      }
  } else {
      return -result;
  }
    }
    /**
     * Convert the bytes within the specified range of the given byte 
     * array into a signed integer . The range extends from 
     * <code>start</code> till, but not including <code>end</code>. <p>
     */
    public static int parseInt(byte[] b, int start, int end)
    throws NumberFormatException {
  return parseInt(b, start, end, 10);
    }
    /**
     * Convert the bytes within the specified range of the given byte 
     * array into a signed long in the given radix . The range extends 
     * from <code>start</code> till, but not including <code>end</code>. <p>
     *
     * Based on java.lang.Long.parseLong()
     */
    public static long parseLong(byte[] b, int start, int end, int radix)
    throws NumberFormatException {
  if (b == null)
      throw new NumberFormatException("null");
  
  long result = 0;
  boolean negative = false;
  int i = start;
  long limit;
  long multmin;
  int digit;
  if (end > start) {
      if (b[i] == "-") {
    negative = true;
    limit = Long.MIN_VALUE;
    i++;
      } else {
    limit = -Long.MAX_VALUE;
      }
      multmin = limit / radix;
      if (i < end) {
    digit = Character.digit((char)b[i++], radix);
    if (digit < 0) {
        throw new NumberFormatException(
      "illegal number: " + toString(b, start, end)
      );
    } else {
        result = -digit;
    }
      }
      while (i < end) {
    // Accumulating negatively avoids surprises near MAX_VALUE
    digit = Character.digit((char)b[i++], radix);
    if (digit < 0) {
        throw new NumberFormatException("illegal number");
    }
    if (result < multmin) {
        throw new NumberFormatException("illegal number");
    }
    result *= radix;
    if (result < limit + digit) {
        throw new NumberFormatException("illegal number");
    }
    result -= digit;
      }
  } else {
      throw new NumberFormatException("illegal number");
  }
  if (negative) {
      if (i > start + 1) {
    return result;
      } else {  /* Only got "-" */
    throw new NumberFormatException("illegal number");
      }
  } else {
      return -result;
  }
    }
    /**
     * Convert the bytes within the specified range of the given byte 
     * array into a signed long . The range extends from 
     * <code>start</code> till, but not including <code>end</code>. <p>
     */
    public static long parseLong(byte[] b, int start, int end)
    throws NumberFormatException {
  return parseLong(b, start, end, 10);
    }
    /**
     * Convert the bytes within the specified range of the given byte 
     * array into a String. The range extends from <code>start</code>
     * till, but not including <code>end</code>. <p>
     */
    public static String toString(byte[] b, int start, int end) {
  int size = end - start;
  char[] theChars = new char[size];
  for (int i = 0, j = start; i < size; )
      theChars[i++] = (char)(b[j++]&0xff);
  
  return new String(theChars);
    }
    public static String toString(ByteArrayInputStream is) {
  int size = is.available();
  char[] theChars = new char[size];
  byte[] bytes    = new byte[size];
  is.read(bytes, 0, size);
  for (int i = 0; i < size;)
      theChars[i] = (char)(bytes[i++]&0xff);
  
  return new String(theChars);
    }

    public static byte[] getBytes(String s) {
  char [] chars= s.toCharArray();
  int size = chars.length;
  byte[] bytes = new byte[size];
      
  for (int i = 0; i < size;)
      bytes[i] = (byte) chars[i++];
  return bytes;
    }
    public static byte[] getBytes(InputStream is) throws IOException {
  int len;
  int size = 1024;
  byte [] buf;

  if (is instanceof ByteArrayInputStream) {
      size = is.available();
      buf = new byte[size];
      len = is.read(buf, 0, size);
  }
  else {
      ByteArrayOutputStream bos = new ByteArrayOutputStream();
      buf = new byte[size];
      while ((len = is.read(buf, 0, size)) != -1)
    bos.write(buf, 0, len);
      buf = bos.toByteArray();
  }
  return buf;
    }
}





QP Encoder Stream

    
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 *
 * Contributor(s):
 *
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don"t indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
/*
 * @(#)QPEncoderStream.java 1.8 07/05/04
 */

import java.io.*;
/**
 * This class implements a Quoted Printable Encoder. It is implemented as
 * a FilterOutputStream, so one can just wrap this class around
 * any output stream and write bytes into this filter. The Encoding
 * is done as the bytes are written out.
 * 
 * @author John Mani
 */
public class QPEncoderStream extends FilterOutputStream {
    private int count = 0;  // number of bytes that have been output
    private int bytesPerLine; // number of bytes per line
    private boolean gotSpace = false;
    private boolean gotCR = false;
    /**
     * Create a QP encoder that encodes the specified input stream
     * @param out        the output stream
     * @param bytesPerLine  the number of bytes per line. The encoder
     *                   inserts a CRLF sequence after this many number
     *                   of bytes.
     */
    public QPEncoderStream(OutputStream out, int bytesPerLine) {
  super(out);
  // Subtract 1 to account for the "=" in the soft-return 
  // at the end of a line
  this.bytesPerLine = bytesPerLine - 1;
    }
    /**
     * Create a QP encoder that encodes the specified input stream.
     * Inserts the CRLF sequence after outputting 76 bytes.
     * @param out        the output stream
     */
    public QPEncoderStream(OutputStream out) {
  this(out, 76);  
    }
    /**
     * Encodes <code>len</code> bytes from the specified
     * <code>byte</code> array starting at offset <code>off</code> to
     * this output stream.
     *
     * @param      b     the data.
     * @param      off   the start offset in the data.
     * @param      len   the number of bytes to write.
     * @exception  IOException  if an I/O error occurs.
     */
    public void write(byte[] b, int off, int len) throws IOException {
  for (int i = 0; i < len; i++)
      write(b[off + i]);
    }
    /**
     * Encodes <code>b.length</code> bytes to this output stream.
     * @param      b   the data to be written.
     * @exception  IOException  if an I/O error occurs.
     */
    public void write(byte[] b) throws IOException {
  write(b, 0, b.length);
    }
    /**
     * Encodes the specified <code>byte</code> to this output stream.
     * @param      c   the <code>byte</code>.
     * @exception  IOException  if an I/O error occurs.
     */
    public void write(int c) throws IOException {
  c = c & 0xff; // Turn off the MSB.
  if (gotSpace) { // previous character was <SPACE>
      if (c == "\r" || c == "\n")
    // if CR/LF, we need to encode the <SPACE> char
    output(" ", true);
      else // no encoding required, just output the char
    output(" ", false);
      gotSpace = false;
  }
  if (c == "\r") {
      gotCR = true;
      outputCRLF();
  } else {
      if (c == "\n") {
    if (gotCR) 
        // This is a CRLF sequence, we already output the 
        // corresponding CRLF when we got the CR, so ignore this
        ;
    else
        outputCRLF();
      } else if (c == " ") {
    gotSpace = true;
      } else if (c < 040 || c >= 0177 || c == "=")
    // Encoding required. 
    output(c, true);
      else // No encoding required
    output(c, false);
      // whatever it was, it wasn"t a CR
      gotCR = false;
  }
    }
    /**
     * Flushes this output stream and forces any buffered output bytes
     * to be encoded out to the stream.
     * @exception  IOException  if an I/O error occurs.
     */
    public void flush() throws IOException {
  out.flush();
    }
    /**
     * Forces any buffered output bytes to be encoded out to the stream
     * and closes this output stream
     */
    public void close() throws IOException {
  out.close();
    }
    private void outputCRLF() throws IOException {
  out.write("\r");
  out.write("\n");
  count = 0;
    }
    // The encoding table
    private final static char hex[] = {
  "0","1", "2", "3", "4", "5", "6", "7",
  "8","9", "A", "B", "C", "D", "E", "F"
    };
    protected void output(int c, boolean encode) throws IOException {
  if (encode) {
      if ((count += 3) > bytesPerLine) {
    out.write("=");
        out.write("\r");
        out.write("\n");
    count = 3; // set the next line"s length
      }
      out.write("=");
      out.write(hex[c >> 4]);
      out.write(hex[c & 0xf]);
  } else {
      if (++count > bytesPerLine) {
    out.write("=");
        out.write("\r");
        out.write("\n");
    count = 1; // set the next line"s length
      }
      out.write(c);
  }
    }
    /**** begin TEST program ***
    public static void main(String argv[]) throws Exception {
        FileInputStream infile = new FileInputStream(argv[0]);
        QPEncoderStream encoder = new QPEncoderStream(System.out);
        int c;
 
        while ((c = infile.read()) != -1)
            encoder.write(c);
        encoder.close();
    }
    *** end TEST program ***/
}
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License. You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 * Sun designates this particular file as subject to the "Classpath" exception
 * as provided by Sun in the GPL Version 2 section of the License file that
 * accompanied this code.  If applicable, add the following below the License
 * Header, with the fields enclosed by brackets [] replaced by your own
 * identifying information: "Portions Copyrighted [year]
 * [name of copyright owner]"
 *
 * Contributor(s):
 *
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don"t indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
/*
 * @(#)ASCIIUtility.java  1.11 07/05/04
 */
 class ASCIIUtility {
    // Private constructor so that this class is not instantiated
    private ASCIIUtility() { }
  
    /**
     * Convert the bytes within the specified range of the given byte 
     * array into a signed integer in the given radix . The range extends 
     * from <code>start</code> till, but not including <code>end</code>. <p>
     *
     * Based on java.lang.Integer.parseInt()
     */
    public static int parseInt(byte[] b, int start, int end, int radix)
    throws NumberFormatException {
  if (b == null)
      throw new NumberFormatException("null");
  
  int result = 0;
  boolean negative = false;
  int i = start;
  int limit;
  int multmin;
  int digit;
  if (end > start) {
      if (b[i] == "-") {
    negative = true;
    limit = Integer.MIN_VALUE;
    i++;
      } else {
    limit = -Integer.MAX_VALUE;
      }
      multmin = limit / radix;
      if (i < end) {
    digit = Character.digit((char)b[i++], radix);
    if (digit < 0) {
        throw new NumberFormatException(
      "illegal number: " + toString(b, start, end)
      );
    } else {
        result = -digit;
    }
      }
      while (i < end) {
    // Accumulating negatively avoids surprises near MAX_VALUE
    digit = Character.digit((char)b[i++], radix);
    if (digit < 0) {
        throw new NumberFormatException("illegal number");
    }
    if (result < multmin) {
        throw new NumberFormatException("illegal number");
    }
    result *= radix;
    if (result < limit + digit) {
        throw new NumberFormatException("illegal number");
    }
    result -= digit;
      }
  } else {
      throw new NumberFormatException("illegal number");
  }
  if (negative) {
      if (i > start + 1) {
    return result;
      } else {  /* Only got "-" */
    throw new NumberFormatException("illegal number");
      }
  } else {
      return -result;
  }
    }
    /**
     * Convert the bytes within the specified range of the given byte 
     * array into a signed integer . The range extends from 
     * <code>start</code> till, but not including <code>end</code>. <p>
     */
    public static int parseInt(byte[] b, int start, int end)
    throws NumberFormatException {
  return parseInt(b, start, end, 10);
    }
    /**
     * Convert the bytes within the specified range of the given byte 
     * array into a signed long in the given radix . The range extends 
     * from <code>start</code> till, but not including <code>end</code>. <p>
     *
     * Based on java.lang.Long.parseLong()
     */
    public static long parseLong(byte[] b, int start, int end, int radix)
    throws NumberFormatException {
  if (b == null)
      throw new NumberFormatException("null");
  
  long result = 0;
  boolean negative = false;
  int i = start;
  long limit;
  long multmin;
  int digit;
  if (end > start) {
      if (b[i] == "-") {
    negative = true;
    limit = Long.MIN_VALUE;
    i++;
      } else {
    limit = -Long.MAX_VALUE;
      }
      multmin = limit / radix;
      if (i < end) {
    digit = Character.digit((char)b[i++], radix);
    if (digit < 0) {
        throw new NumberFormatException(
      "illegal number: " + toString(b, start, end)
      );
    } else {
        result = -digit;
    }
      }
      while (i < end) {
    // Accumulating negatively avoids surprises near MAX_VALUE
    digit = Character.digit((char)b[i++], radix);
    if (digit < 0) {
        throw new NumberFormatException("illegal number");
    }
    if (result < multmin) {
        throw new NumberFormatException("illegal number");
    }
    result *= radix;
    if (result < limit + digit) {
        throw new NumberFormatException("illegal number");
    }
    result -= digit;
      }
  } else {
      throw new NumberFormatException("illegal number");
  }
  if (negative) {
      if (i > start + 1) {
    return result;
      } else {  /* Only got "-" */
    throw new NumberFormatException("illegal number");
      }
  } else {
      return -result;
  }
    }
    /**
     * Convert the bytes within the specified range of the given byte 
     * array into a signed long . The range extends from 
     * <code>start</code> till, but not including <code>end</code>. <p>
     */
    public static long parseLong(byte[] b, int start, int end)
    throws NumberFormatException {
  return parseLong(b, start, end, 10);
    }
    /**
     * Convert the bytes within the specified range of the given byte 
     * array into a String. The range extends from <code>start</code>
     * till, but not including <code>end</code>. <p>
     */
    public static String toString(byte[] b, int start, int end) {
  int size = end - start;
  char[] theChars = new char[size];
  for (int i = 0, j = start; i < size; )
      theChars[i++] = (char)(b[j++]&0xff);
  
  return new String(theChars);
    }
    public static String toString(ByteArrayInputStream is) {
  int size = is.available();
  char[] theChars = new char[size];
  byte[] bytes    = new byte[size];
  is.read(bytes, 0, size);
  for (int i = 0; i < size;)
      theChars[i] = (char)(bytes[i++]&0xff);
  
  return new String(theChars);
    }

    public static byte[] getBytes(String s) {
  char [] chars= s.toCharArray();
  int size = chars.length;
  byte[] bytes = new byte[size];
      
  for (int i = 0; i < size;)
      bytes[i] = (byte) chars[i++];
  return bytes;
    }
    public static byte[] getBytes(InputStream is) throws IOException {
  int len;
  int size = 1024;
  byte [] buf;

  if (is instanceof ByteArrayInputStream) {
      size = is.available();
      buf = new byte[size];
      len = is.read(buf, 0, size);
  }
  else {
      ByteArrayOutputStream bos = new ByteArrayOutputStream();
      buf = new byte[size];
      while ((len = is.read(buf, 0, size)) != -1)
    bos.write(buf, 0, len);
      buf = bos.toByteArray();
  }
  return buf;
    }
}





Represents a collection of 64 boolean (on/off) flags.

    
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import java.io.Serializable;
/**
 * Represents a collection of 64 boolean (on/off) flags.  Individual flags 
 * are represented by powers of 2.  For example,<br/>
 * Flag 1 = 1<br/>
 * Flag 2 = 2<br/>
 * Flag 3 = 4<br/>
 * Flag 4 = 8<br/><br/>
 * or using shift operator to make numbering easier:<br/>
 * Flag 1 = 1 &lt;&lt; 0<br/>
 * Flag 2 = 1 &lt;&lt; 1<br/>
 * Flag 3 = 1 &lt;&lt; 2<br/>
 * Flag 4 = 1 &lt;&lt; 3<br/>
 * 
 * <p>
 * There cannot be a flag with a value of 3 because that represents Flag 1 
 * and Flag 2 both being on/true.
 * </p>
 *
 * @version $Revision: 478334 $ $Date: 2006-11-22 21:31:54 +0000 (Wed, 22 Nov 2006) $
 */
public class Flags implements Serializable {
    /**
     * Represents the current flag state.
     */
    private long flags = 0;
    /**
     * Create a new Flags object.
     */
    public Flags() {
        super();
    }
    /**
     * Initialize a new Flags object with the given flags.
     *
     * @param flags collection of boolean flags to represent.
     */
    public Flags(long flags) {
        super();
        this.flags = flags;
    }
    /**
     * Returns the current flags.
     *
     * @return collection of boolean flags represented.
     */
    public long getFlags() {
        return this.flags;
    }
    /**
     * Tests whether the given flag is on.  If the flag is not a power of 2 
     * (ie. 3) this tests whether the combination of flags is on.
     *
     * @param flag Flag value to check.
     *
     * @return whether the specified flag value is on.
     */
    public boolean isOn(long flag) {
        return (this.flags & flag) > 0;
    }
    /**
     * Tests whether the given flag is off.  If the flag is not a power of 2 
     * (ie. 3) this tests whether the combination of flags is off.
     *
     * @param flag Flag value to check.
     *
     * @return whether the specified flag value is off.
     */
    public boolean isOff(long flag) {
        return (this.flags & flag) == 0;
    }
    /**
     * Turns on the given flag.  If the flag is not a power of 2 (ie. 3) this
     * turns on multiple flags.
     *
     * @param flag Flag value to turn on.
     */
    public void turnOn(long flag) {
        this.flags |= flag;
    }
    /**
     * Turns off the given flag.  If the flag is not a power of 2 (ie. 3) this
     * turns off multiple flags.
     *
     * @param flag Flag value to turn off.
     */
    public void turnOff(long flag) {
        this.flags &= ~flag;
    }
    /**
     * Turn off all flags.
     */
    public void turnOffAll() {
        this.flags = 0;
    }
    
    /**
     * Turn off all flags.  This is a synonym for <code>turnOffAll()</code>.
     * @since Validator 1.1.1
     */
    public void clear() {
        this.flags = 0;
    }
    /**
     * Turn on all 64 flags.
     */
    public void turnOnAll() {
        this.flags = Long.MAX_VALUE;
    }
    /**
     * Clone this Flags object.
     *
     * @return a copy of this object.
     * @see java.lang.Object#clone()
     */
    public Object clone() {
        try {
            return super.clone();
        } catch(CloneNotSupportedException e) {
            throw new RuntimeException("Couldn"t clone Flags object.");
        }
    }
    /**
     * Tests if two Flags objects are in the same state.
     * @param obj object being tested
     * @see java.lang.Object#equals(java.lang.Object)
     *
     * @return whether the objects are equal.
     */
    public boolean equals(Object obj) {
        if (!(obj instanceof Flags)) {
            return false;
        }
        if (obj == this) {
            return true;
        }
        Flags f = (Flags) obj;
        return this.flags == f.flags;
    }
    /**
     * The hash code is based on the current state of the flags.
     * @see java.lang.Object#hashCode()
     *
     * @return the hash code for this object.
     */
    public int hashCode() {
        return (int) this.flags;
    }
    /**
     * Returns a 64 length String with the first flag on the right and the 
     * 64th flag on the left.  A 1 indicates the flag is on, a 0 means it"s 
     * off.
     *
     * @return string representation of this object.
     */
    public String toString() {
        StringBuffer bin = new StringBuffer(Long.toBinaryString(this.flags));
        for (int i = 64 - bin.length(); i > 0; i--) {
            bin.insert(0, "0");
        }
        return bin.toString();
    }
}





to Base64

    
/****************************************************************
 * Licensed to the Apache Software Foundation (ASF) under one   *
 * or more contributor license agreements.  See the NOTICE file *
 * distributed with this work for additional information        *
 * regarding copyright ownership.  The ASF licenses this file   *
 * to you under the Apache License, Version 2.0 (the            *
 * "License"); you may not use this file except in compliance   *
 * with the License.  You may obtain a copy of the License at   *
 *                                                              *
 *   http://www.apache.org/licenses/LICENSE-2.0                 *
 *                                                              *
 * Unless required by applicable law or agreed to in writing,   *
 * software distributed under the License is distributed on an  *
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
 * KIND, either express or implied.  See the License for the    *
 * specific language governing permissions and limitations      *
 * under the License.                                           *
 ****************************************************************/

public class EncodeUtils {
    
    public static final int MASK = 0x3F;
    public static final int FIRST_MASK = MASK << 18; 
    public static final int SECOND_MASK = MASK << 12; 
    public static final int THIRD_MASK = MASK << 6; 
    public static final int FORTH_MASK = MASK; 
    
    public static final byte[] ENCODING = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
        "O", "P" ,"Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i",
        "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3",
        "4", "5", "6", "7", "8", "9", "+", "/"};
    
    public static final void main(String[] args) throws Exception {
        byte[] bytes = {(byte) 0, (byte) 128, (byte) 0};
        System.out.println(new String(toBase64(bytes)));
        System.out.println(new String(toBase64("Hello, World".getBytes())));
        System.out.println(new String(toBase64("Monday".getBytes())));
        System.out.println(new String(toBase64("M\u00F6nchengladbach\r\n".getBytes("ISO-8859-1"))));
    }
    
    public static byte[] toBase64(byte[] in) {
        int inputLength = in.length;
        int outputLength = (int) Math.floor((4*inputLength) / 3f) + 3;
        outputLength = outputLength + 2 * (int) Math.floor(outputLength / 76f);
        byte[] results = new byte[outputLength];
        int inputIndex = 0;
        int outputIndex = 0;
        while (inputLength - inputIndex > 2) {
            int one = (toInt(in[inputIndex++]) << 16);
            int two = (toInt(in[inputIndex++]) << 8);
            int three = toInt(in[inputIndex++]);
            int quantum = one | two | three;
            int index = (quantum & FIRST_MASK) >> 18;
            outputIndex = setResult(results, outputIndex, ENCODING[index]);
            index = (quantum & SECOND_MASK) >> 12;
            outputIndex = setResult(results, outputIndex, ENCODING[index]);
            index = (quantum & THIRD_MASK) >> 6;
            outputIndex = setResult(results, outputIndex, ENCODING[index]);
            index = (quantum & FORTH_MASK);
            outputIndex = setResult(results, outputIndex, ENCODING[index]);
        }
        
        switch (inputLength - inputIndex) {
            case 1:
                int quantum = in[inputIndex++] << 16;
                int index = (quantum & FIRST_MASK) >> 18;
                outputIndex = setResult(results, outputIndex, ENCODING[index]);
                index = (quantum & SECOND_MASK) >> 12;
                outputIndex = setResult(results, outputIndex, ENCODING[index]);
                outputIndex = setResult(results, outputIndex, (byte) "=");
                outputIndex = setResult(results, outputIndex, (byte) "=");
                break;
                
            case 2:
                quantum = (in[inputIndex++] << 16) + (in[inputIndex++] << 8);
                index = (quantum & FIRST_MASK) >> 18;
                outputIndex = setResult(results, outputIndex, ENCODING[index]);
                index = (quantum & SECOND_MASK) >> 12;
                outputIndex = setResult(results, outputIndex, ENCODING[index]);
                index = (quantum & THIRD_MASK) >> 6;
                outputIndex = setResult(results, outputIndex, ENCODING[index]);
                outputIndex = setResult(results, outputIndex, (byte) "=");
                break;
        }
        
        return results;
    }
    private static int toInt(byte b) {
        return 255 & b;
    }

    private static int setResult(byte[] results, int outputIndex, byte value) {
        results[outputIndex++] = value;
        outputIndex = checkLineLength(results, outputIndex);
        return outputIndex;
    }

    private static int checkLineLength(byte[] results, int outputIndex) {
        if (outputIndex == 76 || outputIndex > 76 && (outputIndex - 2*Math.floor(outputIndex/76f - 1)) % 76 == 0) {
            results[outputIndex++] = "\r";
            results[outputIndex++] = "\n";
        }
        return outputIndex;
    }
}