Java/Network Protocol/Base64 Encoding

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

Base64 Content-Transfer-Encoding from RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One

   <source lang="java">
 

/****************************************************************

* 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.FilterOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.HashSet; import java.util.Set; /**

* This class implements section 6.8. Base64 Content-Transfer-Encoding
* from RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One:
* Format of Internet Message Bodies by Freed and Borenstein.
*

* Code is based on Base64 and Base64OutputStream code from Commons-Codec 1.4. * * @see */ public class Base64OutputStream extends FilterOutputStream { // Default line length per RFC 2045 section 6.8. private static final int DEFAULT_LINE_LENGTH = 76; // CRLF line separator per RFC 2045 section 2.1. private static final byte[] CRLF_SEPARATOR = { "\r", "\n" }; // 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. static final byte[] BASE64_TABLE = { "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", "+", "/" }; // Byte used to pad output. private static final byte BASE64_PAD = "="; // This set contains all base64 characters including the pad character. Used // solely to check if a line separator contains any of these characters. private static final Set<Byte> BASE64_CHARS = new HashSet<Byte>(); static { for (byte b : BASE64_TABLE) { BASE64_CHARS.add(b); } BASE64_CHARS.add(BASE64_PAD); } // Mask used to extract 6 bits private static final int MASK_6BITS = 0x3f; private static final int ENCODED_BUFFER_SIZE = 2048; private final byte[] singleByte = new byte[1]; private final int lineLength; private final byte[] lineSeparator; private boolean closed = false; private final byte[] encoded; private int position = 0; private int data = 0; private int modulus = 0; private int linePosition = 0; /** * Creates a Base64OutputStream that writes the encoded data * to the given output stream using the default line length (76) and line * separator (CRLF). * * @param out * underlying output stream. */ public Base64OutputStream(OutputStream out) { this(out, DEFAULT_LINE_LENGTH, CRLF_SEPARATOR); } /** * Creates a Base64OutputStream that writes the encoded data * to the given output stream using the given line length and the default * line separator (CRLF). * <p> * The given line length will be rounded up to the nearest multiple of 4. If * the line length is zero then the output will not be split into lines. * * @param out * underlying output stream. * @param lineLength * desired line length. */ public Base64OutputStream(OutputStream out, int lineLength) { this(out, lineLength, CRLF_SEPARATOR); } /** * Creates a Base64OutputStream that writes the encoded data * to the given output stream using the given line length and line * separator. * <p> * The given line length will be rounded up to the nearest multiple of 4. If * the line length is zero then the output will not be split into lines and * the line separator is ignored. * <p> * The line separator must not include characters from the BASE64 alphabet * (including the padding character =). * * @param out * underlying output stream. * @param lineLength * desired line length. * @param lineSeparator * line separator to use. */ public Base64OutputStream(OutputStream out, int lineLength, byte[] lineSeparator) { super(out); if (out == null) throw new IllegalArgumentException(); if (lineLength < 0) throw new IllegalArgumentException(); checkLineSeparator(lineSeparator); this.lineLength = lineLength; this.lineSeparator = new byte[lineSeparator.length]; System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length); this.encoded = new byte[ENCODED_BUFFER_SIZE]; } @Override public final void write(final int b) throws IOException { if (closed) throw new IOException("Base64OutputStream has been closed"); singleByte[0] = (byte) b; write0(singleByte, 0, 1); } @Override public final void write(final byte[] buffer) throws IOException { if (closed) throw new IOException("Base64OutputStream has been closed"); if (buffer == null) throw new NullPointerException(); if (buffer.length == 0) return; write0(buffer, 0, buffer.length); } @Override public final void write(final byte[] buffer, final int offset, final int length) throws IOException { if (closed) throw new IOException("Base64OutputStream has been closed"); if (buffer == null) throw new NullPointerException(); if (offset < 0 || length < 0 || offset + length > buffer.length) throw new IndexOutOfBoundsException(); if (length == 0) return; write0(buffer, offset, offset + length); } @Override public void flush() throws IOException { if (closed) throw new IOException("Base64OutputStream has been closed"); flush0(); } @Override public void close() throws IOException { if (closed) return; closed = true; close0(); } private void write0(final byte[] buffer, final int from, final int to) throws IOException { for (int i = from; i < to; i++) { data = (data << 8) | (buffer[i] & 0xff); if (++modulus == 3) { modulus = 0; // write line separator if necessary if (lineLength > 0 && linePosition >= lineLength) { // writeLineSeparator() inlined for performance reasons linePosition = 0; if (encoded.length - position < lineSeparator.length) flush0(); for (byte ls : lineSeparator) encoded[position++] = ls; } // encode data into 4 bytes if (encoded.length - position < 4) flush0(); encoded[position++] = BASE64_TABLE[(data >> 18) & MASK_6BITS]; encoded[position++] = BASE64_TABLE[(data >> 12) & MASK_6BITS]; encoded[position++] = BASE64_TABLE[(data >> 6) & MASK_6BITS]; encoded[position++] = BASE64_TABLE[data & MASK_6BITS]; linePosition += 4; } } } private void flush0() throws IOException { if (position > 0) { out.write(encoded, 0, position); position = 0; } } private void close0() throws IOException { if (modulus != 0) writePad(); // write line separator at the end of the encoded data if (lineLength > 0 && linePosition > 0) { writeLineSeparator(); } flush0(); } private void writePad() throws IOException { // write line separator if necessary if (lineLength > 0 && linePosition >= lineLength) { writeLineSeparator(); } // encode data into 4 bytes if (encoded.length - position < 4) flush0(); if (modulus == 1) { encoded[position++] = BASE64_TABLE[(data >> 2) & MASK_6BITS]; encoded[position++] = BASE64_TABLE[(data << 4) & MASK_6BITS]; encoded[position++] = BASE64_PAD; encoded[position++] = BASE64_PAD; } else { assert modulus == 2; encoded[position++] = BASE64_TABLE[(data >> 10) & MASK_6BITS]; encoded[position++] = BASE64_TABLE[(data >> 4) & MASK_6BITS]; encoded[position++] = BASE64_TABLE[(data << 2) & MASK_6BITS]; encoded[position++] = BASE64_PAD; } linePosition += 4; } private void writeLineSeparator() throws IOException { linePosition = 0; if (encoded.length - position < lineSeparator.length) flush0(); for (byte ls : lineSeparator) encoded[position++] = ls; } private void checkLineSeparator(byte[] lineSeparator) { if (lineSeparator.length > ENCODED_BUFFER_SIZE) throw new IllegalArgumentException("line separator length exceeds " + ENCODED_BUFFER_SIZE); for (byte b : lineSeparator) { if (BASE64_CHARS.contains(b)) { throw new IllegalArgumentException( "line separator must not contain base64 character "" + (char) (b & 0xff) + """); } } } } </source>

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

   <source lang="java">
 

/*

* 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.
*/

/**

* 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/> This class implements section 4. Base 64 Encoding with URL and Filename Safe Alphabet
* from RFC 3548 The Base16, Base32, and Base64 Data Encodings 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 0 through 63 accessed by using
  * character encodings as indices. <p/> For example, base64Alphabet["+"] returns
  * 62.
  * </p>
  * <p/> The value of undefined encodings is -1.
  * </p>
  */
 private static byte[] base64Alphabet = new byte[BASELENGTH];
 /**
  * <p/> Contains the Base64 encodings A through Z, followed by
  * a through z, followed by 0 through
  * 9, followed by +, and /.
  * </p>
  * <p/> This array is accessed by using character values as indices.
  * </p>
  * <p/> For example, lookUpBase64Alphabet[62]  returns "+".
  * </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 octet is in the base 64 alphabet.
  * 
  * @param octet
  *            The value to test
  * @return true if the value is defined in the the base 64 alphabet,
  *         false otherwise.
  */
 private static boolean isBase64(byte octet)
 {
   if (octet < 0 || base64Alphabet[octet] == -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 true 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 octets
  * 
  * @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;
   // 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);
 }

}


 </source>
   
  
 
  



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

   <source lang="java">
 

/*

* $Header: /home/cvs/jakarta-commons/codec/src/java/org/apache/commons/codec/binary/Base64.java,v 1.1 2003/04/25 17:50:56 tobrien Exp $
* $Revision: 1.1 $
* $Date: 2003/04/25 17:50:56 $
 *
 * 
 *
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2003 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
 *    Foundation" must not be used to endorse or promote products derived
 *    from this software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache"
 *    nor may "Apache" appear in their names without prior written
 *    permission of the Apache Group.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS"" AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * 
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 *
 * [Additional notices, if required by prior licensing conditions]
 *
 */

/**

 * This class provides encode/decode for RFC 2045 Base64 as
 * defined by RFC 2045, N. Freed and N. Borenstein.  
 * @since 1.0-dev
 *
 */

@SuppressWarnings({"ALL"}) public class Base64 {

   // Create constants pertaining to the chunk requirement
   static final int CHUNK_SIZE = 76;
   static final byte[] CHUNK_SEPARATOR = "\n".getBytes();
   // Create numerical and byte constants
   static final int BASELENGTH = 255;
   static final int LOOKUPLENGTH = 64;
   static final int TWENTYFOURBITGROUP = 24;
   static final int EIGHTBIT = 8;
   static final int SIXTEENBIT = 16;
   static final int SIXBIT = 6;
   static final int FOURBYTE = 4;
   static final int SIGN = -128;
   static final byte PAD = (byte) "=";
   // Create arrays to hold the base64 characters and a
   // lookup for base64 chars
   private static byte[] base64Alphabet = new byte[BASELENGTH];
   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) "/";
   }
   private static boolean isBase64(byte octect) {
       if (octect == PAD) {
           return true;
       }
       else if (base64Alphabet[octect] == -1) {
           return false;
       }
       else {
           return true;
       }
   }
   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;
   }
   public static byte[] encodeBase64(byte[] binaryData) {
       return (encodeBase64(binaryData, false));
   }
   public static byte[] encodeBase64Chunked(byte[] binaryData) {
       return (encodeBase64(binaryData, true));
   }
   public Object decode(Object pObject) throws IllegalArgumentException {
       Object result;
       if (!(pObject instanceof byte[])) {
           throw new IllegalArgumentException(
               "Parameter supplied to "
                   + "Base64 "
                   + "decode is not a byte[]");
       }
       else {
           result = decode((byte[]) pObject);
       }
       return result;
   }
   public byte[] decode(byte[] pArray) throws IllegalArgumentException {
       byte[] result;
       if (!isArrayByteBase64(pArray)) {
           throw new IllegalArgumentException(
               "Parameter supplied to "
                   + "Base64 "
                   + "decode is not a valid base64 data.");
       }
       else {
           result = decodeBase64(pArray);
       }
       return (result);
   }
   /**
    * Encodes hex octects into Base64.
    *
    * @param binaryData Array containing binary data to encode.
    * @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 suggests line wrapping at (no more than) 76
       // characters -- we may have embedded whitespace.
       base64Data = discardWhitespace(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;
   }
   // Implementation of the Encoder Interface
   /**
    * encode an Object
    */
   public Object encode(Object pObject) throws IllegalArgumentException {
       Object result;
       if (!(pObject instanceof byte[])) {
           throw new IllegalArgumentException(
               "Parameter supplied to "
                   + "Base64 "
                   + "encode is not a byte[]");
       }
       else {
           result = encode((byte[]) pObject);
       }
       return result;
   }
   public byte[] encode(byte[] pArray) throws IllegalArgumentException {
       return (encodeBase64(pArray, false));
   }

}


 </source>
   
  
 
  



Provides Base64 encoding and decoding as defined by RFC 2045

   <source lang="java">
 

/*

* Copyright 2001-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.
*/ 


/**

* Provides Base64 encoding and decoding as defined by RFC 2045.
* 
*

This class implements section 6.8. Base64 Content-Transfer-Encoding * from RFC 2045 Multipurpose Internet Mail Extensions (MIME) Part One: * Format of Internet Message Bodies by Freed and Borenstein.

*
* @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) "=";
   // Create arrays to hold the base64 characters and a 
   // lookup for base64 chars
   private static byte[] base64Alphabet = new byte[BASELENGTH];
   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) "/";
   }
   private static boolean isBase64(byte octect) {
       if (octect == PAD) {
           return true;
       } else if (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 true 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 DecoderException if the parameter supplied is not
    *                          of type byte[]
    */
   public Object decode(Object pObject) {
       if (!(pObject instanceof byte[])) {
           throw new RuntimeException("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 isChunked is true 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 EncoderException if the parameter supplied is not
    *                          of type byte[]
    */
   public Object encode(Object pObject) {
       if (!(pObject instanceof byte[])) {
           throw new RuntimeException(
               "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);
   }

}


 </source>
   
  
 
  



Provides encoding of raw bytes to base64-encoded characters, and decoding of base64 characters to raw bytes.

   <source lang="java">
  

/*

* JCommon : a free general purpose class library for the Java(tm) platform
* 
*
* (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
* 
* Project Info:  http://www.jfree.org/jcommon/index.html
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
* USA.  
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
* in the United States and other countries.]
* 
* -------------------------------------
* AbstractElementDefinitionHandler.java
* -------------------------------------
* (C)opyright 2003-2005, by Thomas Morgner and Contributors.
*
* Original Author:  Kevin Kelley <kelley@ruralnet.net> -
*                   30718 Rd. 28, La Junta, CO, 81050  USA. 
*
* $Id: Base64.java,v 1.4 2005/10/18 13:33:53 mungady Exp $
*
* Changes
* -------------------------
* 23.09.2003 : Initial version
*
*/

import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.CharArrayWriter; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; /**

* Provides encoding of raw bytes to base64-encoded characters, and decoding of
* base64 characters to raw bytes. date: 06 August 1998 modified: 14 February
* 2000 modified: 22 September 2000
* 
* @author Kevin Kelley (kelley@ruralnet.net)
* @version 1.3
*/

public class Base64 {

 private 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.
  */
 public static char[] encode(final byte[] data) {
   final 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 & data[i]);
     val <<= 8;
     if ((i + 1) < data.length) {
       val |= (0xFF & data[i + 1]);
       trip = true;
     }
     val <<= 8;
     if ((i + 2) < data.length) {
       val |= (0xFF & 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.
  * 
  * @param data
  *          the character data.
  * 
  * @return The decoded data.
  */
 public static byte[] decode(final 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;
   }
   final 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++) {
     final 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
 //
 private static char[] alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
     .toCharArray();
 //
 // lookup table for converting base64 characters to value in range 0..63
 //
 private static 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.
 // /////////////////////////////////////////////////
 /**
  * Entry point.
  * 
  * @param args
  *          the command line arguments.
  */
 public static void main(final 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;
     }
   }
   final String filename = args[args.length - 1];
   final File file = new File(filename);
   if (!file.exists()) {
     System.out.println("Error:  file "" + filename + "" doesn"t exist!");
     System.exit(0);
   }
   if (decode) {
     final char[] encoded = readChars(file);
     final byte[] decoded = decode(encoded);
     writeBytes(file, decoded);
   } else {
     final byte[] decoded = readBytes(file);
     final char[] encoded = encode(decoded);
     writeChars(file, encoded);
   }
 }
 private static byte[] readBytes(final File file) {
   final ByteArrayOutputStream baos = new ByteArrayOutputStream();
   try {
     final InputStream fis = new FileInputStream(file);
     final InputStream is = new BufferedInputStream(fis);
     int count;
     final 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(final File file) {
   final CharArrayWriter caw = new CharArrayWriter();
   try {
     final Reader fr = new FileReader(file);
     final Reader in = new BufferedReader(fr);
     int count;
     final 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(final File file, final byte[] data) {
   try {
     final OutputStream fos = new FileOutputStream(file);
     final OutputStream os = new BufferedOutputStream(fos);
     os.write(data);
     os.close();
   } catch (Exception e) {
     e.printStackTrace();
   }
 }
 private static void writeChars(final File file, final char[] data) {
   try {
     final Writer fos = new FileWriter(file);
     final Writer os = new BufferedWriter(fos);
     os.write(data);
     os.close();
   } catch (Exception e) {
     e.printStackTrace();
   }
 }
 // /////////////////////////////////////////////////
 // end of test code.
 // /////////////////////////////////////////////////

}


 </source>