Base64编解码C源码

一、Base64是什么?

Base64是一种字节码编码方式,主要是基于64个可打印字符来表示二进制数据的方法,详细介绍请参考百度百科。[百度百科介绍]

二、示例源码(C语言接口)

源程序主要包含base64编码与base64解码接口。main函数主要作为demo展示用,代码里有对文件(比如jpg图片等)编解码操作示例。

#include <stdio.h>
#include <string.h>
#include <math.h>

/* Base64编码映射表 */
const char *const Base64Table = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

/******************************************************** 
 *功能描述:Base64编码
 *输入参数: Bindata:原始bin数据
 			Binlen:原始	bin数据长度
 *输出参数:Base64Buf:base64编码数据
 *返 回 值:base64编码后数据长度
*********************************************************/
int Base64Encode(const unsigned char *Bindata, int Binlen, char *const Base64Buf)
{
	unsigned char s8CharIndex = 0;
    int i=0, Len=0;

    for ((i=0,Len=0); i<Binlen; i+=3)
    {
    	s8CharIndex = (Bindata[i]>>2);
        s8CharIndex &= (unsigned char)0x3F;
        Base64Buf[Len++] = Base64Table[(int)s8CharIndex];

        s8CharIndex = ((unsigned char)(Bindata[i]<<4)) & ((unsigned char)0x30);
        if ((i+1) >= Binlen)
        {
            Base64Buf[Len++] = Base64Table[(int)s8CharIndex];
            Base64Buf[Len++] = '=';
            Base64Buf[Len++] = '=';
            break;
        }
        s8CharIndex |= ((unsigned char)(Bindata[i+1]>>4)) & ((unsigned char)0x0F);
        Base64Buf[Len++] = Base64Table[(int)s8CharIndex];

        s8CharIndex = ((unsigned char)(Bindata[i+1]<<2)) & ((unsigned char)0x3C);
        if ((i+2) >= Binlen)
        {
            Base64Buf[Len++] = Base64Table[(int)s8CharIndex];
            Base64Buf[Len++] = '=';
            break;
        }
        s8CharIndex |= ((unsigned char)(Bindata[i+2]>>6) & ((unsigned char)0x03));
		Base64Buf[Len++] = Base64Table[(int)s8CharIndex];

        s8CharIndex = ((unsigned char)Bindata[i+2]) & ((unsigned char)0x3F) ;
        Base64Buf[Len++] = Base64Table[(int)s8CharIndex];
    }
	
    return Len;
}  

/******************************************************** 
 *功能描述:Base64解码
 *输入参数: Base64Buf:base64编码数据
 *输出参数:Bindata:解码后bin数据
 *返 回 值:解码后bin数据长度
*********************************************************/
int Base64Decode(const char *Base64Buf, unsigned char *const Bindata)
{
    int i, Len=0;
    unsigned char s8CharIndex = 0;
    unsigned char temp[4] = {0};
    for ((i=0,Len=0); Base64Buf[i]!='\0'; i+=4)
    {
        memset(temp, 0xFF, sizeof(temp));
        for (s8CharIndex=0; s8CharIndex<64; s8CharIndex++)
        {
            if (Base64Table[s8CharIndex] == Base64Buf[i])
                temp[0]= s8CharIndex;
        }
		
        for (s8CharIndex=0; s8CharIndex<64; s8CharIndex++)
        {
            if (Base64Table[s8CharIndex] == Base64Buf[i+1])
                temp[1]= s8CharIndex;
        }
		
        for (s8CharIndex=0; s8CharIndex<64; s8CharIndex++)
        {
            if (Base64Table[s8CharIndex] == Base64Buf[i+2])
                temp[2]= s8CharIndex;
        }
		
        for (s8CharIndex=0; s8CharIndex<64; s8CharIndex++)
        {
            if (Base64Table[s8CharIndex] == Base64Buf[i+3])
                temp[3]= s8CharIndex;
        }

		if ((0xFF==temp[0]) || (0xFF==temp[1]) || (0xFF==temp[2]) || (0xFF==temp[3]))
		{
			//printf("(%s:%d) already decode base64 Len:%d\r\n", __func__, __LINE__, i);
			//break;//考虑到有些base64是经过变异的,不做退出处理
		}
		
        Bindata[Len++] = ((unsigned char)(((unsigned char)(temp[0] << 2))&0xFC)) |
                ((unsigned char)((unsigned char)(temp[1]>>4)&0x03));
        if (Base64Buf[i+2] == '=')
        {
        	printf("(%s:%d) already decode base64 Len:%d\r\n", __func__, __LINE__, i);
        	break;
        }

        Bindata[Len++] = ((unsigned char)(((unsigned char)(temp[1] << 4))&0xF0)) |
                ((unsigned char)((unsigned char)(temp[2]>>2)&0x0F));
        if (Base64Buf[i+3] == '=')
        {
        	printf("(%s:%d) already decode base64 Len:%d\r\n", __func__, __LINE__, i);
        	break;
        }
		
        Bindata[Len++] = ((unsigned char)(((unsigned char)(temp[2] << 6))&0xF0)) |
                ((unsigned char)(temp[3]&0x3F));
    }
	
    return Len;
}

int main(int argc, char **argv)
{
	int s32Base64Len = 0;
	int s32BinLen = 0;
	int s32ReadLen = 0;

#if 0 //文件解码
	FILE	 *fpEnc = NULL;
	FILE	 *fpDec = NULL;
	fpEnc = fopen(argv[1], "rb");//打开base64编码后的文件
	if (NULL == fpEnc)
	{
		printf("fopen %s failed.\r\n", argv[1]);
		return 0;
	}
	clearerr(fpEnc);
	fseek(fpEnc, 0, SEEK_END);
    if (0 >= (s32Base64Len=ftell(fpEnc)))
    {
		printf("ftell %d failed.\r\n", s32Base64Len);
		return 0;
	}
	fseek(fpEnc, 0, SEEK_SET);
	
	fpDec = fopen(argv[2], "wb");//打开待保存bin数据
	if (NULL == fpDec)
	{
		printf("fopen %s failed.\r\n", argv[2]);
		return 0;
	}
	clearerr(fpDec);
	
	char Base64buf[s32Base64Len+1];
	unsigned char Binbuf[((int)ceil((double)s32Base64Len/(double)4))*3];

	/*TODO:实际可能一次读取不完或读取出错,所以如果优化要做循环读取一次解码一次的话,
	  需每次读取base64数据长度应为4的整数倍,否则解码会异常 */
	memset(Base64buf, 0x00, sizeof(Base64buf));
	s32ReadLen = fread(Base64buf, 1, s32Base64Len, fpEnc);
	printf("fread Base64 Len=%d.\r\n", s32ReadLen);

	memset(Binbuf, 0x00, sizeof(Binbuf));
	s32BinLen = Base64Decode((const char *)Base64buf, Binbuf);
	printf("Base64Decode BinLen=%d.\r\n", s32BinLen);
	fwrite(Binbuf, 1, s32BinLen, fpDec);

	if (NULL != fpEnc)
	{
		fclose(fpEnc);
		fpEnc = NULL;
	}

	if (NULL != fpDec)
	{	
		fflush(fpDec);
		fclose(fpDec);
		fpDec = NULL;
	}
#elif 0//文件编码
	FILE	 *fpEnc = NULL;
	FILE	 *fpDec = NULL;
	fpEnc = fopen(argv[2], "wb");//打开base64编码后的文件
	if (NULL == fpEnc)
	{
		printf("fopen %s failed.\r\n", argv[1]);
		return 0;
	}
	clearerr(fpEnc);
	
	fpDec = fopen(argv[1], "rb");//打开未编码的源文件
	if (NULL == fpDec)
	{
		printf("fopen %s failed.\r\n", argv[2]);
		return 0;
	}
	clearerr(fpDec);
	
	fseek(fpDec, 0, SEEK_END);
    if (0 >= (s32BinLen=ftell(fpDec)))
    {
		printf("ftell %d failed.\r\n", s32BinLen);
		return 0;
	}
	fseek(fpDec, 0, SEEK_SET);
	
	char Base64buf[((int)ceil((double)s32BinLen/(double)3))*4+1];
	unsigned char Binbuf[s32BinLen];

	memset(Base64buf, 0x00, sizeof(Base64buf));
	memset(Binbuf, 0x00, sizeof(Binbuf));

	/*TODO:实际可能一次读取不完或读取出错,所以如果优化要做循环读取一次解码一次的话,
	  需每次读取base64数据长度应为3的倍数 */
	s32ReadLen = fread(Binbuf, 1, s32BinLen, fpDec);
	printf("fread Bin Len=%d.\r\n", s32ReadLen);
	
	s32Base64Len = Base64Encode(Binbuf, s32BinLen, Base64buf);
	printf("Base64Encode Base64Len=%d.\r\n", s32Base64Len);
	fwrite(Base64buf, 1, s32Base64Len, fpEnc);

	if (NULL != fpDec)
	{
		fclose(fpDec);
		fpDec = NULL;
	}

	if (NULL != fpEnc)
	{	
		fflush(fpEnc);
		fclose(fpEnc);
		fpEnc = NULL;
	}
#elif 1//string编码
	char *pstr = "hello world";
	char Base64buf[((int)ceil((double)strlen(pstr)/(double)3))*4+1];

	memset(Base64buf, 0x00, sizeof(Base64buf));
	s32Base64Len = Base64Encode((const unsigned char*)pstr, strlen(pstr), Base64buf);
	printf("base64:%s,Len:%d\r\n", Base64buf, s32Base64Len);
#endif
}

三、可打印字符表

正是由于Base64是基于64个可打印字符来表示二进制数据的,而对应可打印字符表的索引区间为0-63。所以在编码过程中最关键的是要求把每三个8Bit的字节转换为四个6Bit的字节(3x8 = 4x6 = 24Bit),然后把6Bit高位再添两位0,组成四个8Bit的字节(每个字节所能表示最大区间为0000 0000 <=>0011 1111对应十进制0-63),再将这四个8Bit字节作为可打印字符表索引号,取出索引号对应字符就是我们要的base64编码数据。

索引对应字符索引对应字符索引对应字符索引对应字符
0A17R34i51z
1B18S35j520
2C19T36k531
3D20U37l542
4E21V38m553
5F22W39n564
6G23X40o575
7H24Y41p586
8I25Z42q597
9J26a43r608
10K27b44s619
11L28c45t62+
12M29d46u63/
13N30e47v
14O31f48w
15P32g49x
16Q33h50y



                                                        ------注:文中难免存在文字与内容有遗漏和不妥之处,恳请各位在评论区批评指正,感谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值