Java/Development Class/Base64
Версия от 18:01, 31 мая 2010; (обсуждение)
Содержание
- 1 A Base64 Encoder/Decoder
- 2 A fast and memory efficient class to encode and decode to and from BASE64 in full accordance with RFC 2045
- 3 array of byte to encode
- 4 Base64 Character encoder as specified in RFC1113
- 5 Base64 encoder/decoder
- 6 BASE64 encoder implementation
- 7 Base-64 Encoder - translates from base-64 text into binary
- 8 Base64 encoding/decoding.
- 9 Base64 from by Funambol, Inc.
- 10 Base64 Utils
- 11 byte to be tested if it is Base64 alphabet
- 12 Codes number up to radix 62
- 13 Converting hexadecimal strings
- 14 Convert to hex from byte arrays and back
- 15 Decodes Base64 data into octects
- 16 Encode and decode data in Base64 format as described in RFC 1521
- 17 Encode and decode integers, times, and internationalized strings to and from popular binary formats
- 18 Encode/decode for RFC 2045 Base64 as defined by RFC 2045
- 19 Encode/decode for RFC 2045 Base64 as defined by RFC 2045, N. Freed and N. Borenstein.
- 20 Encodes and decodes to and from Base64 notation.
- 21 Encodes hex octects into Base64
- 22 Encoding of raw bytes to base64-encoded characters, and decoding of base64 characters to raw bytes
- 23 Helper class to provide Base64 encoding routines.
- 24 Implementation of MIME"s Base64 encoding and decoding conversions.
- 25 One of the fastest implementation of the Base64 encoding. Jakarta and others are slower
- 26 Performs Base64 encoding and/or decoding
- 27 Provides Base64 encoding and decoding as defined by RFC 2045
- 28 Provides Base64 encoding and decoding with URL and filename safe alphabet as defined by RFC 3548, section 4.
- 29 Provides utility methods to Base64 encode data
- 30 QP Decoder Stream
- 31 QP Encoder Stream
- 32 Represents a collection of 64 boolean (on/off) flags.
- 33 to Base64
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 (< 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 << 0<br/>
* Flag 2 = 1 << 1<br/>
* Flag 3 = 1 << 2<br/>
* Flag 4 = 1 << 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;
}
}