blob: a9a395e5a036b15a2d0ae34ea94232fee9621387 [file] [log] [blame]
/*
* 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.
*/
package org.apache.pivot.util;
/**
* Implements the "base64" binary encoding scheme as defined by
* <a href="http://tools.ietf.org/html/rfc2045">RFC 2045</a>.
*/
public final class Base64 {
private static final char[] lookup = new char[64];
private static final byte[] reverseLookup = new byte[256];
static {
// Populate the lookup array
for (int i = 0; i < 26; i++) {
lookup[i] = (char)('A' + i);
}
for (int i = 26, j = 0; i < 52; i++, j++) {
lookup[i] = (char)('a' + j);
}
for (int i = 52, j = 0; i < 62; i++, j++) {
lookup[i] = (char)('0' + j);
}
lookup[62] = '+';
lookup[63] = '/';
// Populate the reverse lookup array
for (int i = 0; i < 256; i++) {
reverseLookup[i] = -1;
}
for (int i = 'Z'; i >= 'A'; i--) {
reverseLookup[i] = (byte)(i - 'A');
}
for (int i = 'z'; i >= 'a'; i--) {
reverseLookup[i] = (byte)(i - 'a' + 26);
}
for (int i = '9'; i >= '0'; i--) {
reverseLookup[i] = (byte)(i - '0' + 52);
}
reverseLookup['+'] = 62;
reverseLookup['/'] = 63;
reverseLookup['='] = 0;
}
/**
* This class is not instantiable.
*/
private Base64() {
}
/**
* Encodes the specified data into a base64 string.
*
* @param bytes
* The unencoded raw data.
*/
public static String encode(byte[] bytes) {
StringBuilder buf = new StringBuilder(4 * (bytes.length / 3 + 1));
for (int i = 0, n = bytes.length; i < n; ) {
byte byte0 = bytes[i++];
byte byte1 = (i++ < n) ? bytes[i - 1] : 0;
byte byte2 = (i++ < n) ? bytes[i - 1] : 0;
buf.append(lookup[byte0 >> 2]);
buf.append(lookup[((byte0 << 4) | byte1 >> 4) & 63]);
buf.append(lookup[((byte1 << 2) | byte2 >> 6) & 63]);
buf.append(lookup[byte2 & 63]);
if (i > n) {
for (int m = buf.length(), j = m - (i - n); j < m; j++) {
buf.setCharAt(j, '=');
}
}
}
return buf.toString();
}
/**
* Decodes the specified base64 string back into its raw data.
*
* @param encoded
* The base64 encoded string.
*/
public static byte[] decode(String encoded) {
int padding = 0;
for (int i = encoded.length() - 1; encoded.charAt(i) == '='; i--) {
padding++;
}
int length = encoded.length() * 6 / 8 - padding;
byte[] bytes = new byte[length];
for (int i = 0, index = 0, n = encoded.length(); i < n; i += 4) {
int word = reverseLookup[encoded.charAt(i)] << 18;
word += reverseLookup[encoded.charAt(i + 1)] << 12;
word += reverseLookup[encoded.charAt(i + 2)] << 6;
word += reverseLookup[encoded.charAt(i + 3)];
for (int j = 0; j < 3 && index + j < length; j++) {
bytes[index + j] = (byte)(word >> (8 * (2 - j)));
}
index += 3;
}
return bytes;
}
}