您的位置:首页 > 其它

自定义Base64编码和解码的实现

2015-02-17 18:13 190 查看
今天把之前实现的Base64的过程写出来,这篇文章的思路是这样的,首先使用自然语言及编程语言来描述Base64编码的过程,然后设计编码和解码的接口函数,最后是代码的实现和测试。

编码和解码是以三个字符为一组来处理的,对于字符串长度不是3的倍数的情况在后面再单独介绍。

例子:s13

编码过程:

1.获得每个字符对应的ASCII码值的二进制形式:01110011 00110001 00110011;

2.将上面的3组8位二进制划分成四组6位二进制的形式:011100 110011 000100 110011

3.高位补零得到4组8位的二进制的形式:00011100 00110011
00000100 00110011

4.根据这四组二进制所对应的十进制值到编码表中索引出字符:c z E z。

上述编码过程中需要我们实现的有:将3组8位二进制转换成4组6位二进制,再高位补0;到编码表中索引出对应的字符。

01110011 00110001 00110011截取第一个字节的前6位得到011100,然后第一个字节的最后两位和第二个字节的前四位组合而成110011,再将第二个字节的后4位和第三个字节的前两位组合成000100,最后由第三个字节的后6位得到110011。

先复习下java中移位运算符的知识:<<(左移),>>(带符号右移)和>>>(无符号右移)。

移位运算符是在二进制的基础上对数字进行平移的,由于移动的方向和填充方式的不同分为上面3种。

举个例子:00110011,对应左移2位:00110011<<2,得到11001100,在其低位补0即可。

>>(带符号右移)的运算规则是:低位舍弃,高位补符号位,即正数补0,负数补1。>>>(无符号右移)就是右移对应位数,低位舍弃,高位全部补0。

下面用编程语言来描述编码过程:

1.s13对应的字节为byte[0]:01110011,byte[1]:00110001,byte[2]:00110011。

2.byte[0]无符号右移2位,byte[0]>>>2得到编码后的第一个字节;

3.byte[0]与0x03(00000011)按位与&,这样高6位全为0,再左移4位,将byte[1]>>>4,最后将byte[0]和byte[1]按位或|,得到编码后第二个字节;

4.将byte[1]与0x0f(00001111)按位与&,这样byte[1]的高4位就为0了,这样做的目的是byte[1]的高四位我们现在不需要,然后左移2位,将byte[2]>>>6,因为我们需要byte[2]的低2位。最后将byte[1]和byte[1]进行按位或|操作,得到编码后的第三个字节。

5.将byte[2]的后6位截取,即byte[2]与0x3f按位与&,这样就得到了编码后的第四个字节。

6.根据这四个字节对应的值到编码转换表中查找其所对应的字符。

对于特殊情况:字符串的长度不是3的倍数,剩余1或2个字符。采取的做法是:若剩余1个字符,将该字符转换出2个,若剩余2个字符,将该字符转换出3个,不够补0,最后用=来填充满4个字符。

举个例子:s 对应的二进制为01110011,截取高6位得到00011100,然后最后两位再补零得到一个字节110000,高位补0,即00110000然后补两个=,所以s编码后为cw==。

ss对应的二进制为01110011 01110011,按照之前的规则得到011100 110111 ,0011再通过补0,得到001100,然后填充=,所以ss编码后为c3M=。对于这两种特殊情况,在编程时特殊考虑。

现在我们来考虑编码接口设计(解码与之类似):

public interface Base64 {

/**
* 将要编码的字符串的字节编码后返回编码后得到字符串
*
* @param b:要编码的字符串字节数组
* @return 编码后的字符串
*/
public abstract String encode(byte[] b);

/**
* 将三个字节中的第一个截取到前6位,得到编码后的第一字节
*
* @param b:三个字节中的第一个
* @return 编码后的第一字节
*/
public abstract byte firstByte(byte b);

/**
* 联合三个字节中的第一个和第二个得到编码后的第二个字节
*
* @param last_b:第一个字节    next_b:第二个字节
* @return  编码后的第二个字节
*/
public abstract byte secondByte(byte last_b,byte next_b);

/**
* 联合三个字节中的第二个和第三个得到编码后的第三个字节
*
* @param last_b:第二个字节   next_b:第三个字节
* @return 编码后的第三个字节
*/
public abstract byte thirdByte(byte last_b,byte next_b);

/**
* 将三个字节中的第三个字节截取后6位,得到编码后的第四个字节
*
* @param b:第三个字节
* @return 编码后的第四个字节
*/
public abstract byte fourthByte(byte b);

/**
* 处理特殊情况:字符串长度%3!=0
*
*/
public abstract byte lastOneByte(byte b,int move);

}
以上函数之间的关系是:外界通过调用encode函数来完成编码,在encode函数内部:首先考虑是否出现特殊情况(字符串长度不是3的倍数),若未出现,就以3个字节为一组来处理字符串:依次调用firstByte,secondByte,thirdByte,fourthByte来得到编码后的四个字节,最后将其转换成编码表中对应的字符即可。若出现特殊情况,在每3个字节为一组在处理完之后,通过lastOneByte来处理剩余的1个或2个字节。

下面先是实现firstByte,secondByte,thirdByte,fourthByte这四个函数,这四个函数就是实现对3个字节的移位运算,来得到4个编码后的字节。

@Override
public byte firstByte(byte b) {
//对字节b右移2位
int r_f=b & 0xff;
r_f=r_f >>> 2;
return (byte)(r_f & 0x3f);
}

@Override
public byte secondByte(byte last_b, byte next_b) {
//取last_b的低2位和next_b的高4位
int r_l=last_b & 0xff;
int r_n=next_b & 0xff;
r_l=last_b & 0x03;//last_b去掉高6位
r_l=r_l << 4;//last_b左移4位
r_n=r_n >>> 4;//next_b右移4位

return (byte)((r_l | r_n) & 0x3f);
}

@Override
public byte thirdByte(byte last_b, byte next_b) {
//取last_b的低4位和next_b的高2位
int r_l=last_b & 0xff;
int r_n=next_b & 0xff;
r_l=r_l & 0x0f;//last_b去掉高4位
r_l=r_l << 2;//last_b左移2位
r_n=r_n >>> 6;//next_b右移6位

return (byte)((r_l | r_n) & 0x3f);
}

@Override
public byte fourthByte(byte b) {
//取b的低6位
int r_b=b & 0xff;
r_b=r_b << 2;
r_b=r_b >>> 2;

return (byte)(r_b & 0x3f);
}
我们通过firstByte,secondByte,thirdByte,fourthByte这四个函数得到的是四个索引,对应到编码转换表中才得到了编码后的字符。所以我们需要先把编码转换表在代码中实现,下面我们使用一个字节数组来存放字符的ASCII码的二进制。
private static final byte base[] = { 0x41, 0x42, 0x43, 0x44, 0x45, 0x46,
0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51,
0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x61, 0x62,
0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7a, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
0x39, 0x2b, 0x2f };
在encode函数中,根据firstByte,secondByte,thirdByte,fourthByte得到的值找到byte []中对应的值。

@Override
public byte lastOneByte(byte b, int move) {
int r_b = b & 0xff;
r_b = r_b << move;
r_b = r_b >>> 2;
return (byte) (r_b & 0x3f);
}


@Override
public String encode(byte[] b) {
StringBuffer sb = new StringBuffer();
int len = b.length;
int more_len = len % 3;
int use_len = len - more_len;
byte[] bytes = new byte[4];
for (int i = 0; i < use_len; i += 3) {
bytes[0] = base[firstByte(b[i])];
bytes[1] = base[secondByte(b[i], b[i + 1])];
bytes[2] = base[thirdByte(b[i + 1], b[i + 2])];
bytes[3] = base[fourthByte(b[i + 2])];
sb.append(new String(bytes));
}
if (more_len == 1) {
byte b_2[] = new byte[2];
b_2[0] = base[firstByte(b[len - 1])];
b_2[1] = base[lastOneByte(b[len - 1], 6)];
sb.append(new String(b_2));
return sb.append("==").toString();
} else if (more_len == 2) {
byte b_3[] = new byte[3];
b_3[0] = base[firstByte(b[len - 2])];
b_3[1] = base[secondByte(b[len - 2], b[len - 1])];
b_3[2] = base[lastOneByte(b[len - 1], 4)];
sb.append(new String(b_3));
return sb.append("=").toString();
}
return sb.toString();
}
以上整个编码函数的实现就完成了,对于解码的实现下面直接给出代码。
@Override
public byte baseIndex(byte b) {
for (int i = 0; i < base.length; i++) {
if (base[i] == b) {
return (byte) i;
}
}
return -1;
}

@Override
public byte backLastOne(byte last_b, byte next_b, int move_l, int move_b) {
int r_l = last_b & 0xff;
int r_n = next_b & 0xff;
r_l = r_l << move_l;
r_n = r_n << move_b;
r_n = r_n >>> move_b;
return (byte) ((r_l | r_n) & 0xff);
}

@Override
public byte backFirst(byte first, byte second) {
int r_f = first & 0xff;
int r_s = second & 0xff;
r_f = r_f << 2;
r_s = r_s >>> 4;
return (byte) ((r_f | r_s) & 0xff);
}

@Override
public byte backSecond(byte second, byte third) {
int r_s = second & 0xff;
int r_t = third & 0xff;
r_s = r_s << 4;
r_t = r_t >>> 2;
return (byte) ((r_s | r_t) & 0xff);
}

@Override
public byte backThird(byte third, byte fourth) {
int r_t = third & 0xff;
int r_f = fourth & 0xff;
r_t = r_t << 6;
return (byte) ((r_t | r_f) & 0xff);
}

@Override
public String backEncode(byte[] b) {
StringBuffer sb = new StringBuffer();
Vector<Byte> list = new Vector<Byte>();
int real_len = b.length;
int len = real_len - 2;
int more_len = len & 3;
int use_len = len - more_len;
for (int i = 0; i < use_len; i += 4) {
list.add(backFirst(baseIndex(b[i]), baseIndex(b[i + 1])));
list.add(backSecond(baseIndex(b[i + 1]), baseIndex(b[i + 2])));
list.add(backThird(baseIndex(b[i + 2]), baseIndex(b[i + 3])));
}
Enumeration e = list.elements();
byte bytes[] = new byte[list.size()];
int k = -1;
while (e.hasMoreElements()) {
bytes[++k] = (Byte) e.nextElement();
}
sb.append(new String(bytes));
if (more_len == 2) {
byte b_1[] = new byte[1];
b_1[0] = backLastOne(baseIndex(b[len - 2]), baseIndex(b[len - 1]),
2, 6);
sb.append(new String(b_1));
}
if (more_len == 3) {
byte b_2[] = new byte[2];
b_2[0] = backFirst(baseIndex(b[len - 3]), baseIndex(b[len - 2]));
b_2[1] = backLastOne(baseIndex(b[len - 2]), baseIndex(b[len - 1]),
4, 4);
sb.append(new String(b_2));
}
return sb.toString();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: