把资料用base64进行转码

把文件用base64进行转码

一直很好奇base64的实现,ubuntu也自带了base64工具,这篇帖子是对base64的很好解释,http://www.linandxin.com/archives/876 ,特别要注意的是:base64有自己的转码表,并不是跟ascii码表一样的,

今天自己写了一个base64转码的程序,包括编码和解码程序,整个过程让我觉得自己的C语言功底非常的弱,free的时候竟然出现 double free的错误,后来查了一下,原来是因为溢出,超出了malloc的大小

/*****************************************************************
	> File Name: t.c
	> Author: Lobo Chim
	> Mail: zhanlongbo@gmail.com 
	> Created Time: 2013年01月25日 星期五 18时07分39秒
 ****************************************************************/

#include <stdio.h>
#include <memory.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>

#define MAX_SIZE (10 * 1024 * 1024)   //max size 10M

unsigned char *table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

void my_err(const char *s,int line)
{
	fprintf(stderr,"line:%d ",line);
	perror(s);
	exit(1);
}

/*
 * translate 4B to 3B
 * p is start index in f,q is start index in t
 */
void f2t(unsigned char *f,unsigned char *t,int p,int q)
{
	int i;
	for(i=q;i<3+q;i++)
		t[i]=0x00;

	t[q]=f[p]<<2;
	t[q]|=(f[p+1]& 0x30)>>4;
	t[q+1]=f[p+1]<<4;
	t[q+1]|=(f[p+2] & 0x3c)>>2;
	t[q+2]=f[p+2]<<6;
	t[q+2]|=f[p+3] & 0x3f;
}

/*
 * translate 3B to 4B
 * p is start index in t,q is in f
 */
void t2f(unsigned char *t,unsigned char * const f,int p,int q)
{
	int i;
	for(i=q;i<4+q;i++)
		f[i]=0x00;

	f[q]=(t[p]>>2) & 0x3f;
	f[q+1]=(t[p]<<4) & 0x30;
	f[q+1]|=(t[p+1]>>4) & 0x0f;
	f[q+2]=(t[p+1]<<2) & 0x3c;
	f[q+2]|=(t[p+2]>>6) & 0x03;
	f[q+3]=t[p+2] & 0x3f;
}

/*
 * change base64 string to byte
 * return:number of byte
 */
int decode(unsigned char *s,unsigned char *b)
{
	int len=strlen(s);
	int i,j;

	int other=0;  //except a-zA-Z+/=
	//change string to key in table
	for(i=0;i<len;i++)
	{
		if(s[i]=='=')
			s[i]=(unsigned char)0;
		else
		{
			for(j=0;j<64;j++)
				if(s[i]==table[j])
 					break;
			if(j==64)
			{
 				other++;
				continue;
			}
			s[i-other]=(unsigned char)j;
		}
	}

	//change the key to byte
	for(i=0,j=0;i<len-other;i+=4,j+=3)
			f2t(s,b,i,j);

	return j;
}

/*
 *byte to base64
 *return :number of string base64,include new line '\n'
 */
int encode(unsigned char *b,unsigned char *s,int n)
{
	int m=n/3;
	if(n%3)
		m++;

	// may overflow,it is very dangerous!!!
	unsigned char *p=(unsigned char *)malloc(m*4);
	memset(p,0,m*4);

	int i,j;
	for(i=0,j=0;i<m*3;i+=3,j+=4)
		t2f(b,p,i,j);

	// not enough, =
	if(n%3==1)
	{
		p[m*3-1]=(unsigned char)0x40;
		p[m*3-2]=(unsigned char)0x40;
	}
	else if(n%3==2)
	{
		p[m*3-1]=(unsigned char)0x40;
	}

//	printf("m:%d\n",m*4);
	for(i=0,j=0;j<m*4;i++,j++)
	{
		if(j && j%76==0)   //new line
		{
			s[i++]='\n';
		}
				s[i]=table[p[j]];
	}

//	printf("m*4:%d\n",m*4);
	s[i++]='\n';
//	printf("i:%d\n",i);

//	printf("free\n");
//	if(p)
	free(p);
	p=NULL;

//	printf("free ok\n");
	return i;
}

int main(int argc,unsigned char *argv[])
{
	int flag;

	if(argc!=4)
	{
		perror("argc is not 3\n");
		exit(1);
	}
	if(strcmp(argv[1],"-e")==0)
		flag=1;
	else if(strcmp(argv[1],"-d")==0)
		flag=2;
	else
	{
		my_err("usage: ./a.out [optione] file1 file2",__LINE__);
	}
	
	int rf=open(argv[2],O_RDONLY);
	int wf=open(argv[3],O_RDWR|O_CREAT,0644);

	if(rf<0 || wf<0)
	{
		my_err("open fail",__LINE__);
	}

	int SIZE=lseek(rf,0,SEEK_END);
	if(SIZE>MAX_SIZE)
	{
		my_err("file size is too big",__LINE__);
	}
	lseek(rf,0,SEEK_SET);

//	printf("SIZE:%d\n",SIZE);
	int PER=1024;
	unsigned char buf[PER];
	unsigned char *s=(unsigned char *)malloc(SIZE * 2);
	unsigned char *b=(unsigned char *)malloc(SIZE * 2);
	int n,p,i;
	if(s==NULL || b==NULL)
	{
		my_err("malloc fail",__LINE__);
	}

	switch(flag)
	{
		case 1:
			p=0;
			while((n=read(rf,buf,PER))>0)
			{
				memcpy(s+p,buf,n);
		 		p+=n; 
			}
		//	printf("%d\n",p);
			p=encode(s,b,p);
			
			for(i=0;i<p;i++)
				write(wf,b+i,1);
			break;

		case 2:
			p=0;
			while((n=read(rf,buf,PER))>0)
			{
				memcpy(s+p,buf,n);
				p+=n; 
			}
			s[p]='\0';
			p=decode(s,b);
			
			for(i=0;i<p;i+=3)
			{
				write(wf,b+i,3);
			}
			break;
	}

	free(s);
	s=NULL;
	free(b);
	b=NULL;
	close(rf);
	close(wf);
	return 0;
}

longbo@ubuntu:~/lab$ ./a.out -e d.jpg c.txt        编码
longbo@ubuntu:~/lab$ ./a.out -d c.txt c            解码 
longbo@ubuntu:~/lab$ diff d.jpg c                  比较原来的图片和经过编码解码后的图片有没有区别
黑白烂苹果,很喜欢的一张图片


把资料用base64进行转码