// Copyright (C) 2011 - Will Glozer. All rights reserved.
package peergos.shared.scrypt.com.lambdaworks.codec;
import java.util.Arrays;
/**
* High-performance base64 codec based on the algorithm used in Mikael Grev's MiG Base64.
* This implementation is designed to handle base64 without line splitting and with
* optional padding. Alternative character tables may be supplied to the {@code encode}
* and {@code decode} methods to implement modified base64 schemes.
*
* Decoding assumes correct input, the caller is responsible for ensuring that the input
* contains no invalid characters.
*
* @author Will Glozer
*/
public class Base64 {
private static final char[] encode = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
private static final int[] decode = new int[128];
private static final char pad = '=';
static {
Arrays.fill(decode, -1);
for (int i = 0; i < encode.length; i++) {
decode[encode[i]] = i;
}
decode[pad] = 0;
}
/**
* Decode base64 chars to bytes.
*
* @param chars Chars to encode.
*
* @return Decoded bytes.
*/
public static byte[] decode(char[] chars) {
return decode(chars, decode, pad);
}
/**
* Encode bytes to base64 chars, with padding.
*
* @param bytes Bytes to encode.
*
* @return Encoded chars.
*/
public static char[] encode(byte[] bytes) {
return encode(bytes, encode, pad);
}
/**
* Encode bytes to base64 chars, with optional padding.
*
* @param bytes Bytes to encode.
* @param padded Add padding to output.
*
* @return Encoded chars.
*/
public static char[] encode(byte[] bytes, boolean padded) {
return encode(bytes, encode, padded ? pad : 0);
}
/**
* Decode base64 chars to bytes using the supplied decode table and padding
* character.
*
* @param src Base64 encoded data.
* @param table Decode table.
* @param pad Padding character.
*
* @return Decoded bytes.
*/
public static byte[] decode(char[] src, int[] table, char pad) {
int len = src.length;
if (len == 0) return new byte[0];
int padCount = (src[len - 1] == pad ? (src[len - 2] == pad ? 2 : 1) : 0);
int bytes = (len * 6 >> 3) - padCount;
int blocks = (bytes / 3) * 3;
byte[] dst = new byte[bytes];
int si = 0, di = 0;
while (di < blocks) {
int n = table[src[si++]] << 18 | table[src[si++]] << 12 | table[src[si++]] << 6 | table[src[si++]];
dst[di++] = (byte) (n >> 16);
dst[di++] = (byte) (n >> 8);
dst[di++] = (byte) n;
}
if (di < bytes) {
int n = 0;
switch (len - si) {
case 4: n |= table[src[si+3]];
case 3: n |= table[src[si+2]] << 6;
case 2: n |= table[src[si+1]] << 12;
case 1: n |= table[src[si]] << 18;
}
for (int r = 16; di < bytes; r -= 8) {
dst[di++] = (byte) (n >> r);
}
}
return dst;
}
/**
* Encode bytes to base64 chars using the supplied encode table and with
* optional padding.
*
* @param src Bytes to encode.
* @param table Encoding table.
* @param pad Padding character, or 0 for no padding.
*
* @return Encoded chars.
*/
public static char[] encode(byte[] src, char[] table, char pad) {
int len = src.length;
if (len == 0) return new char[0];
int blocks = (len / 3) * 3;
int chars = ((len - 1) / 3 + 1) << 2;
int tail = len - blocks;
if (pad == 0 && tail > 0) chars -= 3 - tail;
char[] dst = new char[chars];
int si = 0, di = 0;
while (si < blocks) {
int n = (src[si++] & 0xff) << 16 | (src[si++] & 0xff) << 8 | (src[si++] & 0xff);
dst[di++] = table[(n >>> 18) & 0x3f];
dst[di++] = table[(n >>> 12) & 0x3f];
dst[di++] = table[(n >>> 6) & 0x3f];
dst[di++] = table[n & 0x3f];
}
if (tail > 0) {
int n = (src[si] & 0xff) << 10;
if (tail == 2) n |= (src[++si] & 0xff) << 2;
dst[di++] = table[(n >>> 12) & 0x3f];
dst[di++] = table[(n >>> 6) & 0x3f];
if (tail == 2) dst[di++] = table[n & 0x3f];
if (pad != 0) {
if (tail == 1) dst[di++] = pad;
dst[di] = pad;
}
}
return dst;
}
}