Java/Data Type/String Base64
Версия от 18:01, 31 мая 2010; (обсуждение)
Class decodes a Base64 encoded string back into the original byte
/*
* Copyright 2005 Ralf Joachim
*
* 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;
/**
* Class decodes a Base64 encoded string back into the original byte representation
* that can be read as byte array.
*
* @author
* @version $Revision: 6907 $ $Date: 2005-08-05 13:58:36 -0600 (Fri, 05 Aug 2005) $
* @since 0.9.9
*/
public final class Base64Decoder {
/** Mask buffer to or with first sextet. */
private static final int SEXTET_1_MASK = 0x03FFFF;
/** Mask buffer to or with second sextet. */
private static final int SEXTET_2_MASK = 0xFC0FFF;
/** Mask buffer to or with third sextet. */
private static final int SEXTET_3_MASK = 0xFFF03F;
/** Mask buffer to or with forth sextet. */
private static final int SEXTET_4_MASK = 0xFFFFC0;
/** Number of bits to shift for one sextet. */
private static final int SHIFT_1_SEXTET = 6;
/** Number of bits to shift for two sextet. */
private static final int SHIFT_2_SEXTET = 12;
/** Number of bits to shift for three sextet. */
private static final int SHIFT_3_SEXTET = 18;
/** Second sextets in buffer. */
private static final int SEXTET_2 = 2;
/** Third sextets in buffer. */
private static final int SEXTET_3 = 3;
/** Forth sextets in buffer. */
private static final int SEXTET_4 = 4;
/** Mask an octet. */
private static final int OCTET_MASK = 0xFF;
/** Number of bits to shift for one octet. */
private static final int SHIFT_1_OCTET = 8;
/** Number of bits to shift for two octet. */
private static final int SHIFT_2_OCTET = 16;
/** White space character (out of range 0 - 63). */
private static final byte SPC = 127;
/** Padding character (out of range 0 - 63). */
private static final byte PAD = 64;
/** Array to translate base64 characters into sextet byte values. */
private static final byte[] MAP = {
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // 00-07
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // 08-0F
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // 10-17
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // 18-1F
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // 20-27
SPC, SPC, SPC, 62, SPC, SPC, SPC, 63, // 28-2F " + /"
52, 53, 54, 55, 56, 57, 58, 59, // 30-37 "01234567"
60, 61, SPC, SPC, SPC, PAD, SPC, SPC, // 38-3F "89 = "
SPC, 0, 1, 2, 3, 4, 5, 6, // 40-47 " ABCDEFG"
7, 8, 9, 10, 11, 12, 13, 14, // 48-4F "HIJKLMNO"
15, 16, 17, 18, 19, 20, 21, 22, // 50-57 "PQRSTUVW"
23, 24, 25, SPC, SPC, SPC, SPC, SPC, // 58-5F "XYZ "
SPC, 26, 27, 28, 29, 30, 31, 32, // 60-67 " abcdefg"
33, 34, 35, 36, 37, 38, 39, 40, // 68-6F "hijklmno"
41, 42, 43, 44, 45, 46, 47, 48, // 70-77 "pqrstuvw"
49, 50, 51, SPC, SPC, SPC, SPC, SPC, // 78-7F "xyz "
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // 80-87
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // 88-8F
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // 90-97
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // 98-9F
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // A0-A7
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // A8-AF
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // B0-B7
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // B8-BF
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // C0-C7
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // C8-CF
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // D0-D7
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // D8-DF
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // E0-E7
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // E8-EF
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // F0-F7
SPC, SPC, SPC, SPC, SPC, SPC, SPC, SPC, // F8-FF
};
/** 24-bit buffer to translate 4 sextets into 3 octets. */
private int _buffer = 0;
/** Number of octets in buffer. */
private int _sextets = 0;
/** Stream buffer for decoded octets waiting to be read. */
private ByteArrayOutputStream _stream = new ByteArrayOutputStream();
/**
* Decode given string into a decoded byte array.
*
* @param str Base64 String to be decoded.
* @return All decoded octets as byte array.
*/
public static byte[] decode(final String str) {
Base64Decoder dec = new Base64Decoder();
dec.translate(str);
return dec.getByteArray();
}
/**
* Construct a default Base64Decoder waiting on calls to its translate()
* method.
*/
public Base64Decoder() { }
/**
* Translate every base64 character from given string into a sextet byte value
* by using above translation array. The sextets are then shiftet into an buffer
* until the buffer contains 4 sextets which are then decoded into 3 octets.
* The translate and decode process is continued until all characters of given
* string are evaluated. If there are remaing sextets in the buffer they also
* will be converted into octets at the end. All the converted octets are added
* to the list for later read.
*
* @param string Base64 String to be decoded.
*/
public void translate(final String string) {
int len = string.length();
int index = 0;
int data = MAP[string.charAt(index)];
while ((index < len) && (data != PAD)) {
if (data != SPC) {
if (_sextets == 0) {
_buffer = (_buffer & SEXTET_1_MASK) | (data << SHIFT_3_SEXTET);
} else if (_sextets == 1) {
_buffer = (_buffer & SEXTET_2_MASK) | (data << SHIFT_2_SEXTET);
} else if (_sextets == 2) {
_buffer = (_buffer & SEXTET_3_MASK) | (data << SHIFT_1_SEXTET);
} else {
_buffer = (_buffer & SEXTET_4_MASK) | data;
}
if ((++_sextets) == SEXTET_4) { decode(); }
}
if (++index < len) { data = MAP[string.charAt(index)]; }
}
if (_sextets > 0) { decodeWithPadding(); }
}
/**
* Decode 3 octets from buffer and add them to list of octets to read.
*/
private void decode() {
_stream.write((byte) ((_buffer >> SHIFT_2_OCTET) & OCTET_MASK)); // octet 1
_stream.write((byte) ((_buffer >> SHIFT_1_OCTET) & OCTET_MASK)); // octet 2
_stream.write((byte) (_buffer & OCTET_MASK)); // octet 3
_buffer = 0;
_sextets = 0;
}
/**
* Decode the remaining octets from buffer and add them to list of octets to read.
*/
private void decodeWithPadding() {
if (_sextets >= SEXTET_2) { // octet 1
_stream.write((byte) ((_buffer >> SHIFT_2_OCTET) & OCTET_MASK));
}
if (_sextets >= SEXTET_3) { // octet 2
_stream.write((byte) ((_buffer >> SHIFT_1_OCTET) & OCTET_MASK));
}
if (_sextets >= SEXTET_4) { // octet 3
_stream.write((byte) (_buffer & OCTET_MASK));
}
_buffer = 0;
_sextets = 0;
}
/**
* Get all decoded octets as byte array.
*
* @return All decoded octets as byte array.
*/
public byte[] getByteArray() {
return _stream.toByteArray();
}
}
Convert a base16 string into a byte array.
/*
* 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.
*/
/**
* Base 16 encoder.
*
* @author Marc Prud"hommeaux
* @nojavadoc
*/
class Base16Encoder {
private final static char[] HEX = new char[]{
"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "A", "B", "C", "D", "E", "F" };
/**
* Convert bytes to a base16 string.
*/
public static String encode(byte[] byteArray) {
StringBuffer hexBuffer = new StringBuffer(byteArray.length * 2);
for (int i = 0; i < byteArray.length; i++)
for (int j = 1; j >= 0; j--)
hexBuffer.append(HEX[(byteArray[i] >> (j * 4)) & 0xF]);
return hexBuffer.toString();
}
/**
* Convert a base16 string into a byte array.
*/
public static byte[] decode(String s) {
int len = s.length();
byte[] r = new byte[len / 2];
for (int i = 0; i < r.length; i++) {
int digit1 = s.charAt(i * 2), digit2 = s.charAt(i * 2 + 1);
if (digit1 >= "0" && digit1 <= "9")
digit1 -= "0";
else if (digit1 >= "A" && digit1 <= "F")
digit1 -= "A" - 10;
if (digit2 >= "0" && digit2 <= "9")
digit2 -= "0";
else if (digit2 >= "A" && digit2 <= "F")
digit2 -= "A" - 10;
r[i] = (byte) ((digit1 << 4) + digit2);
}
return r;
}
}
Convert bytes to a base16 string.
/*
* 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.
*/
/**
* Base 16 encoder.
*
* @author Marc Prud"hommeaux
* @nojavadoc
*/
class Base16Encoder {
private final static char[] HEX = new char[]{
"0", "1", "2", "3", "4", "5", "6", "7",
"8", "9", "A", "B", "C", "D", "E", "F" };
/**
* Convert bytes to a base16 string.
*/
public static String encode(byte[] byteArray) {
StringBuffer hexBuffer = new StringBuffer(byteArray.length * 2);
for (int i = 0; i < byteArray.length; i++)
for (int j = 1; j >= 0; j--)
hexBuffer.append(HEX[(byteArray[i] >> (j * 4)) & 0xF]);
return hexBuffer.toString();
}
/**
* Convert a base16 string into a byte array.
*/
public static byte[] decode(String s) {
int len = s.length();
byte[] r = new byte[len / 2];
for (int i = 0; i < r.length; i++) {
int digit1 = s.charAt(i * 2), digit2 = s.charAt(i * 2 + 1);
if (digit1 >= "0" && digit1 <= "9")
digit1 -= "0";
else if (digit1 >= "A" && digit1 <= "F")
digit1 -= "A" - 10;
if (digit2 >= "0" && digit2 <= "9")
digit2 -= "0";
else if (digit2 >= "A" && digit2 <= "F")
digit2 -= "A" - 10;
r[i] = (byte) ((digit1 << 4) + digit2);
}
return r;
}
}