package com.wangyin.ak47.common;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Byte-related helper class
*
* Byte相关的所有方法,特别是编解码中必须用到
*
* @author hannyu
*
*/
public class ByteUtil {
private static final String C64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; //default base64.
private static final char[] BASE16 = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}, BASE64 = C64.toCharArray();
private static final int MASK4 = 0x0f, MASK6 = 0x3f, MASK8 = 0xff;
private static final Map<Integer, byte[]> DECODE_TABLE_MAP = new ConcurrentHashMap<Integer, byte[]>();
/**
* Merge a List of byte[] to one big byte[].
*
* 合并多个byte[] list
*
* @param bs a collection of byte[]
* @return merged byte[], or byte[0]. Never return null.
*/
public static byte[] merge(List<byte[]> bs){
int len = 0;
for(int i=0; i<bs.size(); i++){
len += bs.get(i).length;
}
byte[] merged = new byte[len];
int x = 0;
for(int i=0; i<bs.size(); i++){
byte[] b = bs.get(i);
int blen = b.length;
// copy(byte[] src, int srcPos, byte[] dest, int destPos, int length)
copy(b, 0, merged, x, blen);
x += blen;
}
return merged;
}
/**
* Merge multiple byte[] to one big byte[].
*
* 合并多个byte[] array
*
* @param bs a collection of byte[]
* @return merged byte[], or byte[0]. Never return null.
*/
public static byte[] merge(byte[]... bs){
int len = 0;
for(int i=0; i<bs.length; i++){
len += bs[i].length;
}
byte[] merged = new byte[len];
int x = 0;
for(int i=0; i<bs.length; i++){
byte[] b = bs[i];
int blen = b.length;
// copy(byte[] src, int srcPos, byte[] dest, int destPos, int length)
copy(b, 0, merged, x, blen);
x += blen;
}
return merged;
}
/**
* byte array copy.
*
* @param src source of byte[]
* @param length length of bytes to be copied
* @return copied byte[]
*/
public static byte[] copyOf(byte[] src, int length)
{
return copyOf(src, 0, length);
}
/**
* byte array copy.
*
* @param src source of byte[]
* @param offset from where to start
* @param length length of bytes to be copied
* @return copied byte[]
*/
public static byte[] copyOf(byte[] src, int offset, int length){
byte[] dest = new byte[length];
System.arraycopy(src, offset, dest, 0, length);
return dest;
}
/**
* copy bytes from src to dest
*
* @param src source
* @param srcPos source position
* @param dest destination
* @param destPos destination position
* @param length length
*/
public static void copy(byte[] src, int srcPos, byte[] dest, int destPos, int length){
System.arraycopy(src, srcPos, dest, destPos, length);
}
/**
* copy bytes from src to dest
*
* @param src source
* @param dest destination
* @param destPos destination position
*/
public static void copy(byte[] src, byte[] dest, int destPos){
System.arraycopy(src, 0, dest, destPos, src.length);
}
/**
* dest[destPos] = src;
*
* @param src source
* @param dest destination
* @param destPos destination position
*/
public static void copy(byte src, byte[] dest, int destPos){
dest[destPos] = src;
}
/**
* to byte array.
*
* @param v value.
* @return byte[].
*/
public static byte[] short2bytes(short v)
{
byte[] ret = { 0, 0 };
short2bytes(v, ret);
return ret;
}
/**
* to byte array.
*
* @param v value.
* @param b byte array.
*/
public static void short2bytes(short v, byte[] b)
{
short2bytes(v, b, 0);
}
/**
* to byte array.
*
* @param v value.
* @param b byte array.
* @param off cursor.
*/
public static void short2bytes(short v, byte[] b, int off)
{
b[off + 1] = (byte) v;
b[off + 0] = (byte) (v >>> 8);
}
/**
* to byte array.
*
* @param v value.
* @return byte[].
*/
public static byte[] int2bytes(int v)
{
byte[] ret = { 0, 0, 0, 0 };
int2bytes(v, ret);
return ret;
}
/**
* to byte array.
*
* @param v value.
* @param b byte array.
*/
public static void int2bytes(int v, byte[] b)
{
int2bytes(v, b, 0);
}
/**
* to byte array.
*
* @param v value.
* @param b byte array.
* @param off array offset.
*/
public static void int2bytes(int v, byte[] b, int off)
{
b[off + 3] = (byte) v;
b[off + 2] = (byte) (v >>> 8);
b[off + 1] = (byte) (v >>> 16);
b[off + 0] = (byte) (v >>> 24);
}
/**
* to byte array.
*
* @param v value.
* @return byte[].
*/
public static byte[] float2bytes(float v)
{
byte[] ret = { 0, 0, 0, 0 };
float2bytes(v, ret);
return ret;
}
/**
* to byte array.
*
* @param v value.
* @param b byte array.
*/
public static void float2bytes(float v, byte[] b)
{
float2bytes(v, b, 0);
}
/**
* to byte array.
*
* @param v value.
* @param b byte array.
* @param off array offset.
*/
public static void float2bytes(float v, byte[] b, int off)
{
int i = Float.floatToIntBits(v);
b[off + 3] = (byte) i;
b[off + 2] = (byte) (i >>> 8);
b[off + 1] = (byte) (i >>> 16);
b[off + 0] = (byte) (i >>> 24);
}
/**
* to byte array.
*
* @param v value.
* @return byte[].
*/
public static byte[] long2bytes(long v)
{
byte[] ret = { 0, 0, 0, 0, 0, 0, 0, 0 };
long2bytes(v, ret);
return ret;
}
/**
* to byte array.
*
* @param v value.
* @param b byte array.
*/
public static void long2bytes(long v, byte[] b)
{
long2bytes(v, b, 0);
}
/**
* to byte array.
*
* @param v value.
* @param b byte array.
* @param off array offset.
*/
public static void long2bytes(long v, byte[] b, int off)
{
b[off + 7] = (byte) v;
b[off + 6] = (byte) (v >>> 8);
b[off + 5] = (byte) (v >>> 16);
b[off + 4] = (byte) (v >>> 24);
b[off + 3] = (byte) (v >>> 32);
b[off + 2] = (byte) (v >>> 40);
b[off + 1] = (byte) (v >>> 48);
b[off + 0] = (byte) (v >>> 56);
}
/**
* to byte array.
*
* @param v value.
* @return byte[].
*/
public static byte[] double2bytes(double v)
{
byte[] ret = { 0, 0, 0, 0, 0, 0, 0, 0 };
double2bytes(v, ret);
return ret;
}
/**
* to byte array.
*
* @param v value.
* @param b byte array.
*/
public static void double2bytes(double v, byte[] b)
{
double2bytes(v, b, 0);
}
/**
* to byte array.
*
* @param v value.
* @param b byte array.
* @param off array offset.
*/
public static void double2bytes(double v, byte[] b, int off)
{
long j = Double.doubleToLongBits(v);
b[off + 7] = (byte) j;
b[off + 6] = (byte) (j >>> 8);
b[off + 5] = (byte) (j >>> 16);
b[off + 4] = (byte) (j >>> 24);
b[off + 3] = (byte) (j >>> 32);
b[off + 2] = (byte) (j >>> 40);
b[off + 1] = (byte) (j >>> 48);
b[off + 0] = (byte) (j >>> 56);
}
/**
* to short.
*
* @param b byte array.
* @return short.
*/
public static short bytes2short(byte[] b)
{
return bytes2short(b, 0);
}
/**
* to short.
*
* @param b byte array.
* @param off offset.
* @return short.
*/
public static short bytes2short(byte[] b, int off)
{
return (short) (((b[off + 1] & 0xFF) << 0) +
((b[off + 0]) << 8));
}
/**
* to int.
*
* @param b byte array.
* @return int.
*/
public static int bytes2int(byte[] b)
{
return bytes2int(b, 0);
}
/**
* to int.
*
* @param b byte array.
* @param off offset.
* @return int.
*/
public static int bytes2int(byte[] b, int off)
{
return ((b[off + 3] & 0xFF) << 0) +
((b[off + 2] & 0xFF) << 8) +
((b[off + 1] & 0xFF) << 16) +
((b[off + 0]) << 24);
}
/**
* to int.
*
* @param b byte array.
* @return int.
*/
public static float bytes2float(byte[] b)
{
return bytes2float(b, 0);
}
/**
* to int.
*
* @param b byte array.
* @param off offset.
* @return int.
*/
public static float bytes2float(byte[] b, int off)
{
int i = ((b[off + 3] & 0xFF) << 0) +
((b[off + 2] & 0xFF) << 8) +
((b[off + 1] & 0xFF) << 16) +
((b[off + 0]) << 24);
return Float.intBitsToFloat(i);
}
/**
* to long.
*
* @param b byte array.
* @return long.
*/
public static long bytes2long(byte[] b)
{
return bytes2long(b,0);
}
/**
* to long.
*
* @param b byte array.
* @param off offset.
* @return long.
*/
public static long bytes2long(byte[] b,int off)
{
return ((b[off + 7] & 0xFFL) << 0) +
((b[off + 6] & 0xFFL) << 8) +
((b[off + 5] & 0xFFL) << 16) +
((b[off + 4] & 0xFFL) << 24) +
((b[off + 3] & 0xFFL) << 32) +
((b[off + 2] & 0xFFL) << 40) +
((b[off + 1] & 0xFFL) << 48) +
(((long) b[off + 0]) << 56);
}
/**
* to long.
*
* @param b byte array.
* @return double.
*/
public static double bytes2double(byte[] b)
{
return bytes2double(b,0);
}
/**
* to long.
*
* @param b byte array.
* @param off offset.
* @return double.
*/
public static double bytes2double(byte[] b, int off)
{
long j = ((b[off + 7] & 0xFFL) << 0) +
((b[off + 6] & 0xFFL) << 8) +
((b[off + 5] & 0xFFL) << 16) +
((b[off + 4] & 0xFFL) << 24) +
((b[off + 3] & 0xFFL) << 32) +
((b[off + 2] & 0xFFL) << 40) +
((b[off + 1] & 0xFFL) << 48) +
(((long) b[off + 0]) << 56);
return Double.longBitsToDouble(j);
}
/**
* to String
*
* @param b byte array
* @param off offset
* @param len length
* @param encoding encoding
* @return String
* @throws UnsupportedEncodingException encoding wrong
*/
public static String bytes2String(byte[] b, int off, int len, String encoding)
throws UnsupportedEncodingException{
return new String(b, off, len, encoding);
}
/**
* to String with UTF-8 encoding
*
* @param b byte array
* @param off offset
* @param len length
* @return String
* @throws UnsupportedEncodingException encoding wrong
*/
public static String bytes2String(byte[] b, int off, int len)
throws UnsupportedEncodingException{
return bytes2String(b, off, len, Ak47Constants.DEFAULT_ENCODING);
}
/**
* to String with UTF-8 encoding
*
* @param b byte array
* @return String
* @throws UnsupportedEncodingException encoding wrong
*/
public static String bytes2String(byte[] b)
throws UnsupportedEncodingException{
return new String(b, Ak47Constants.DEFAULT_ENCODING);
}
/**
* to String with specific encoding
*
* @param b byte array
* @param encoding encoding
* @return String
* @throws UnsupportedEncodingException encoding wrong
*/
public static String bytes2String(byte[] b, String encoding)
throws UnsupportedEncodingException{
return new String(b, encoding);
}
/**
* from String to byte[] with UTF-8 encoding
*
* @param str String
* @return bytes
* @throws UnsupportedEncodingException encoding wrong
*/
public static byte[] string2Bytes(String str)
throws UnsupportedEncodingException{
return string2Bytes(str, Ak47Constants.DEFAULT_ENCODING);
}
/**
* from String to byte[] with specific encoding
*
* @param str String
* @param encoding encoding
* @return bytes
* @throws UnsupportedEncodingException encoding wrong
*/
public static byte[] string2Bytes(String str, String encoding)
throws UnsupportedEncodingException{
return str.getBytes(encoding);
}
/**
* to hex string.
*
* @param bs byte array.
* @return hex string.
*/
public static String bytes2hex(byte[] bs)
{
return bytes2hex(bs, 0, bs.length);
}
/**
* to hex string.
*
* @param bs byte array.
* @param off offset.
* @param len length.
* @return hex string.
*/
public static String bytes2hex(byte[] bs, int off, int len)
{
if( off < 0 )
throw new IndexOutOfBoundsException("bytes2hex: offset < 0, offset is " + off );
if( len < 0 )
throw new IndexOutOfBoundsException("bytes2hex: length < 0, length is " + len );
if( off + len > bs.length )
throw new IndexOutOfBoundsException("bytes2hex: offset + length > array length.");
byte b;
int r = off, w = 0;
char[] cs = new char[len*2];
for(int i=0;i<len;i++)
{
b = bs[r++];
cs[w++] = BASE16[ b >> 4 & MASK4 ];
cs[w++] = BASE16[ b & MASK4 ];
}
return new String(cs);
}
/**
* from hex string.
*
* @param str hex string.
* @return byte array.
*/
public static byte[] hex2bytes(String str)
{
return hex2bytes(str, 0, str.length());
}
/**
* from hex string.
*
* @param str hex string.
* @param off offset.
* @param len length.
* @return byte array.
*/
public static byte[] hex2bytes(final String str, final int off, int len)
{
if( ( len & 1 ) == 1 )
throw new IllegalArgumentException("hex2bytes: ( len & 1 ) == 1.");
if( off < 0 )
throw new IndexOutOfBoundsException("hex2bytes: offset < 0, offset is " + off );
if( len < 0 )
throw new IndexOutOfBoundsException("hex2bytes: length < 0, length is " + len );
if( off + len > str.length() )
throw new IndexOutOfBoundsException("hex2bytes: offset + length > array length.");
int num = len / 2, r = off, w = 0;
byte[] b = new byte[num];
for(int i=0;i<num;i++) {
b[w++] = (byte)( hex(str.charAt(r++)) << 4 | hex(str.charAt(r++)) );
}
return b;
}
/**
* to human-friendly string.
*
* @param bs byte array.
* @return hex string.
*/
public static String bytes2human(byte[] bs)
{
return bytes2human(bs, 0, bs.length);
}
/**
* to human-friendly string.
*
* @param bs byte array.
* @param off offset.
* @param len length.
* @return hex string.
*/
public static String bytes2human(byte[] bs, int off, int len)
{
if( off < 0 )
throw new IndexOutOfBoundsException("bytes2human: offset < 0, offset is " + off );
if( len < 0 )
throw new IndexOutOfBoundsException("bytes2human: length < 0, length is " + len );
if( off + len > bs.length )
throw new IndexOutOfBoundsException("bytes2human: offset + length > array length.");
byte b;
int r = off, w = 0;
char[] cs = new char[len*4];
for(int i=0;i<len;i++)
{
b = bs[r++];
cs[w++] = '\\';
cs[w++] = 'x';
cs[w++] = BASE16[ b >> 4 & MASK4 ];
cs[w++] = BASE16[ b & MASK4 ];
}
return new String(cs);
}
/**
* from human-friendly string.
*
* @param str hex string.
* @return byte array.
*/
public static byte[] human2bytes(String str)
{
return human2bytes(str, 0, str.length());
}
/**
* from human string.
*
* @param str hex string.
* @param off offset.
* @param len length.
* @return byte array.
*/
public static byte[] human2bytes(final String str, final int off, int len)
{
if( ( len & 1 ) == 1 )
throw new IllegalArgumentException("human2bytes: ( len & 1 ) == 1.");
if( off < 0 )
throw new IndexOutOfBoundsException("human2bytes: offset < 0, offset is " + off );
if( len < 0 )
throw new IndexOutOfBoundsException("human2bytes: length < 0, length is " + len );
if( off + len > str.length() )
throw new IndexOutOfBoundsException("human2bytes: offset + length > array length.");
int num = len / 4, r = off, w = 0;
byte[] b = new byte[num];
for(int i=0;i<num;i++) {
r+=2;
b[w++] = (byte)( hex(str.charAt(r++)) << 4 | hex(str.charAt(r++)) );
}
return b;
}
/**
* to base64 string.
*
* @param b byte array.
* @return base64 string.
*/
public static String bytes2base64(byte[] b)
{
return bytes2base64(b, 0, b.length, BASE64);
}
/**
*
*
* @param b byte array.
* @return base64 string.
*/
/**
* to base64 string.
*
* @param b byte array
* @param offset offset
* @param length length
* @return base64 string
*/
public static String bytes2base64(byte[] b, int offset, int length)
{
return bytes2base64(b, offset, length, BASE64);
}
/**
* to base64 string.
*
* @param b byte array.
* @param code base64 code string(0-63 is base64 char,64 is pad char).
* @return base64 string.
*/
public static String bytes2base64(byte[] b, String code)
{
return bytes2base64(b, 0, b.length, code);
}
/**
* to base64 string.
*
* @param b byte array
* @param offset offset
* @param length length
* @param code base64 code string(0-63 is base64 char,64 is pad char)
* @return base64 string
*/
public static String bytes2base64(byte[] b, int offset, int length, String code)
{
if( code.length() < 64 )
throw new IllegalArgumentException("Base64 code length < 64.");
return bytes2base64(b, offset, length, code.toCharArray());
}
/**
* to base64 string.
*
* @param b byte array.
* @param code base64 code(0-63 is base64 char,64 is pad char).
* @return base64 string.
*/
public static String bytes2base64(byte[] b, char[] code)
{
return bytes2base64(b, 0, b.length, code);
}
/**
* to base64 string.
*
* @param bs byte array.
* @param off offset.
* @param len length.
* @param code base64 code(0-63 is base64 char,64 is pad char).
* @return base64 string.
*/
public static String bytes2base64(final byte[] bs, final int off, final int len, final char[] code)
{
if( off < 0 )
throw new IndexOutOfBoundsException("bytes2base64: offset < 0, offset is " + off );
if( len < 0 )
throw new IndexOutOfBoundsException("bytes2base64: length < 0, length is " + len );
if( off + len > bs.length )
throw new IndexOutOfBoundsException("bytes2base64: offset + length > array length.");
if( code.length < 64 )
throw new IllegalArgumentException("Base64 code length < 64.");
boolean pad = code.length > 64; // has pad char.
int num = len / 3, rem = len % 3, r = off, w = 0;
char[] cs = new char[ num * 4 + ( rem == 0 ? 0 : pad ? 4 : rem + 1 ) ];
for(int i=0;i<num;i++)
{
int b1 = bs[r++] & MASK8, b2 = bs[r++] & MASK8, b3 = bs[r++] & MASK8;
cs[w++] = code[ b1 >> 2 ];
cs[w++] = code[ ( b1 << 4 ) & MASK6 | ( b2 >> 4 ) ];
cs[w++] = code[ ( b2 << 2 ) & MASK6 | ( b3 >> 6 ) ];
cs[w++] = code[ b3 & MASK6 ];
}
if( rem == 1 )
{
int b1 = bs[r++] & MASK8;
cs[w++] = code[ b1 >> 2 ];
cs[w++] = code[ ( b1 << 4 ) & MASK6 ];
if( pad )
{
cs[w++] = code[64];
cs[w++] = code[64];
}
}
else if( rem == 2 )
{
int b1 = bs[r++] & MASK8, b2 = bs[r++] & MASK8;
cs[w++] = code[ b1 >> 2 ];
cs[w++] = code[ ( b1 << 4 ) & MASK6 | ( b2 >> 4 ) ];
cs[w++] = code[ ( b2 << 2 ) & MASK6 ];
if( pad )
cs[w++] = code[64];
}
return new String(cs);
}
/**
* from base64 string.
*
* @param str base64 string.
* @return byte array.
*/
public static byte[] base642bytes(String str)
{
return base642bytes(str, 0, str.length());
}
/**
* from base64 string.
*
* @param str base64 string.
* @param offset offset.
* @param length length.
* @return byte array.
*/
public static byte[] base642bytes(String str, int offset, int length)
{
return base642bytes(str, offset, length, C64);
}
/**
* from base64 string.
*
* @param str base64 string.
* @param code base64 code(0-63 is base64 char,64 is pad char).
* @return byte array.
*/
public static byte[] base642bytes(String str, String code)
{
return base642bytes(str, 0, str.length(), code);
}
/**
* from base64 string.
*
* @param str base64 string.
* @param off offset.
* @param len length.
* @param code base64 code(0-63 is base64 char,64 is pad char).
* @return byte array.
*/
public static byte[] base642bytes(final String str, final int off, final int len, final String code)
{
if( off < 0 )
throw new IndexOutOfBoundsException("base642bytes: offset < 0, offset is " + off );
if( len < 0 )
throw new IndexOutOfBoundsException("base642bytes: length < 0, length is " + len );
if( off + len > str.length() )
throw new IndexOutOfBoundsException("base642bytes: offset + length > string length.");
if( code.length() < 64 )
throw new IllegalArgumentException("Base64 code length < 64.");
int rem = len % 4;
if( rem == 1 )
throw new IllegalArgumentException("base642bytes: base64 string length % 4 == 1.");
int num = len / 4, size = num * 3;
if( code.length() > 64 )
{
if( rem != 0 )
throw new IllegalArgumentException("base642bytes: base64 string length error.");
char pc = code.charAt(64);
if( str.charAt(off+len-2) == pc )
{
size -= 2;
--num;
rem = 2;
}
else if( str.charAt(off+len-1) == pc )
{
size--;
--num;
rem = 3;
}
}
else
{
if( rem == 2 )
size++;
else if( rem == 3 )
size += 2;
}
int r = off, w = 0;
byte[] b = new byte[size], t = decodeTable(code);
for(int i=0;i<num;i++)
{
int c1 = t[str.charAt(r++)], c2 = t[str.charAt(r++)];
int c3 = t[str.charAt(r++)], c4 = t[str.charAt(r++)];
b[w++] = (byte)( ( c1 << 2 ) | ( c2 >> 4 ) );
b[w++] = (byte)( ( c2 << 4 ) | ( c3 >> 2 ) );
b[w++] = (byte)( ( c3 << 6 ) | c4 );
}
if( rem == 2 )
{
int c1 = t[str.charAt(r++)], c2 = t[str.charAt(r++)];
b[w++] = (byte)( ( c1 << 2 ) | ( c2 >> 4 ) );
}
else if( rem == 3 )
{
int c1 = t[str.charAt(r++)], c2 = t[str.charAt(r++)], c3 = t[str.charAt(r++)];
b[w++] = (byte)( ( c1 << 2 ) | ( c2 >> 4 ) );
b[w++] = (byte)( ( c2 << 4 ) | ( c3 >> 2 ) );
}
return b;
}
/**
* from base64 string.
*
* @param str base64 string.
* @param code base64 code(0-63 is base64 char,64 is pad char).
* @return byte array.
*/
public static byte[] base642bytes(String str, char[] code)
{
return base642bytes(str, 0, str.length(), code);
}
/**
* from base64 string.
*
* @param str base64 string.
* @param off offset.
* @param len length.
* @param code base64 code(0-63 is base64 char,64 is pad char).
* @return byte array.
*/
public static byte[] base642bytes(final String str, final int off, final int len, final char[] code)
{
if( off < 0 )
throw new IndexOutOfBoundsException("base642bytes: offset < 0, offset is " + off );
if( len < 0 )
throw new IndexOutOfBoundsException("base642bytes: length < 0, length is " + len );
if( off + len > str.length() )
throw new IndexOutOfBoundsException("base642bytes: offset + length > string length.");
if( code.length < 64 )
throw new IllegalArgumentException("Base64 code length < 64.");
int rem = len % 4;
if( rem == 1 )
throw new IllegalArgumentException("base642bytes: base64 string length % 4 == 1.");
int num = len / 4, size = num * 3;
if( code.length > 64 )
{
if( rem != 0 )
throw new IllegalArgumentException("base642bytes: base64 string length error.");
char pc = code[64];
if( str.charAt(off+len-2) == pc )
size -= 2;
else if( str.charAt(off+len-1) == pc )
size--;
}
else
{
if( rem == 2 )
size++;
else if( rem == 3 )
size += 2;
}
int r = off, w = 0;
byte[] b = new byte[size];
for(int i=0;i<num;i++)
{
int c1 = indexOf(code, str.charAt(r++)), c2 = indexOf(code, str.charAt(r++));
int c3 = indexOf(code, str.charAt(r++)), c4 = indexOf(code, str.charAt(r++));
b[w++] = (byte)( ( c1 << 2 ) | ( c2 >> 4 ) );
b[w++] = (byte)( ( c2 << 4 ) | ( c3 >> 2 ) );
b[w++] = (byte)( ( c3 << 6 ) | c4 );
}
if( rem == 2 )
{
int c1 = indexOf(code, str.charAt(r++)), c2 = indexOf(code, str.charAt(r++));
b[w++] = (byte)( ( c1 << 2 ) | ( c2 >> 4 ) );
}
else if( rem == 3 )
{
int c1 = indexOf(code, str.charAt(r++)), c2 = indexOf(code, str.charAt(r++)), c3 = indexOf(code, str.charAt(r++));
b[w++] = (byte)( ( c1 << 2 ) | ( c2 >> 4 ) );
b[w++] = (byte)( ( c2 << 4 ) | ( c3 >> 2 ) );
}
return b;
}
private static byte hex(char c)
{
if( c <= '9' ) return (byte)( c - '0' );
if( c >= 'a' && c <= 'f' ) return (byte)( c - 'a' + 10 );
if( c >= 'A' && c <= 'F' ) return (byte)( c - 'A' + 10 );
throw new IllegalArgumentException("hex string format error [" + c + "].");
}
private static int indexOf(char[] cs, char c)
{
for(int i=0,len=cs.length;i<len;i++)
if( cs[i] == c ) return i;
return -1;
}
private static byte[] decodeTable(String code)
{
int hash = code.hashCode();
byte[] ret = DECODE_TABLE_MAP.get(hash);
if( ret == null )
{
if( code.length() < 64 )
throw new IllegalArgumentException("Base64 code length < 64.");
// create new decode table.
ret = new byte[128];
for(int i=0;i<128;i++) // init table.
ret[i] = -1;
for(int i=0;i<64;i++)
ret[code.charAt(i)] = (byte)i;
DECODE_TABLE_MAP.put(hash, ret);
}
return ret;
}
private ByteUtil(){}
}