c言語でドラッグ&ドロップでbase64のエンコードとデコードしたかったので作りました。

コードは無駄に長くなっています。

前に作ったことはあるのですが、あのときは全てメモリ上で扱っていたためサイズが大きいと扱えなかったため、今回はファイルに3バイトずつ書き込むことで改善しています。

あとシフト演算子の優先順位の考えを理解していなく、結構詰まりました。

もうシフト演算子を使うときは括弧でくくりまくります。

ファイル名やディレクトリの操作を自分で行っているため全角文字が含まれている場合に対応していません。

githubにあげればいいのですが、githubよりこっちの方が見返しやすいので。


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


//0:directory, 1:file
void getFileName(char *filepath,char *getname,int flag)
{
	//get size and '\' count
	int size=0,slash=0;
	for(int i=0;;i++){
		if(filepath[i]==0)break;
		size++;
		if(filepath[i]=='\\')slash++;
	}
	//1:file
	if(flag==1){
		//get file name (reverse)
		char temp[200]={};
		int j=0;
		for(int i=size-1;i>0;i--){
			if(filepath[i]=='\\')break;
			temp[j]=filepath[i];
			j++;
		}
		//put file name
		for(int i=0;;i++){
			if(j<0 || temp[j-1]=='\"'){
				getname[i]=0;
				break;
			}
			getname[i]=temp[j-1];
			j--;
		}
	}else{
		//0:directory
		int slash2=0;
		for(int i=0;;i++){
			if(filepath[i]=='\\')slash2++;
			if(slash2==slash){
				getname[i]=0;
				break;
			}
			getname[i]=filepath[i];
		}
	}
}


int b64table(int b64)
{
	int ascii=-1;
	//0~9 48~57 -> 52~61
	if (b64 >= 48 && b64 <= 57)ascii = b64 + 4;
	//A~Z 65~90 -> 0~25
	if (b64 >= 65 && b64 <= 90)ascii = b64 - 65;
	//a~z 97~122 -> 26~51
	if (b64 >= 97 && b64 <= 122)ascii = b64 - 71;
	//'+' 43 -> 62
	if (b64 == 43)ascii = b64 + 19;
	//'/' 47 -> 63
	if (b64 == 47)ascii = b64 + 16;
	//'=' 61 -> 0
	if (b64 == 61)ascii = 0;
	//error
	if (b64 == -1)printf("ascii=%d\n",b64);
	return ascii;
}


//4 characters(4*6=24 bits)
void b64decode(char *fname)
{
	FILE *fp,*fp2;
	fp=fopen(fname,"rb");
	char fname2[200],fname3[200];
	getFileName(fname,fname2,0);
	getFileName(fname,fname3,1);
	strcat(fname2,"\\b64de_");
	strcat(fname2,fname3);
	fp2=fopen(fname2,"wb");
	

	int de1,de2,de3;
	while(1){
		int a=fgetc(fp);
		if(a==-1)break;
		int b=fgetc(fp);
		int c=fgetc(fp);
		int d=fgetc(fp);
		de1=(b64table(a)<<2)+(b64table(b)>>4);
		de2=((b64table(b)&0b1111)<<4)+(b64table(c)>>2);
		de3=((b64table(c)&0b11)<<6)+b64table(d);
		fputc(de1,fp2);
		fputc(de2,fp2);
		fputc(de3,fp2);
	}
	fclose(fp);
	fclose(fp2);
}


//3 characters(3*8=24 bits)
void b64encode(char *fname)
{
	char base64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
	FILE *fp,*fp2;
	fp=fopen(fname,"rb");
	char fname2[200],fname3[200];
	getFileName(fname,fname2,0);
	getFileName(fname,fname3,1);
	strcat(fname2,"\\b64en_");
	strcat(fname2,fname3);
	fp2=fopen(fname2,"wb");
	

	int en1,en2,en3,en4;
	while(1){
		int a=fgetc(fp);
		if(a==-1)break;
		int b=fgetc(fp);
		if(b==-1){
			en1=base64[a>>2];
			en2=base64[(a&0b11)<<4];
			fputc(en1,fp2);
			fputc(en2,fp2);
			fputc('=',fp2);
			fputc('=',fp2);
			break;
		}
		int c=fgetc(fp);
		if(c==-1){
			en1=base64[a>>2];
			en2=base64[((a&0b11)<<4)+(b>>4)];
			en3=base64[(b&0b1111)<<2];
			fputc(en1,fp2);
			fputc(en2,fp2);
			fputc(en3,fp2);
			fputc('=',fp2);
			break;
		}
		en1=base64[a>>2];
		en2=base64[((a&0b11)<<4)+(b>>4)];
		en3=base64[((b&0b1111)<<2)+(c>>6)];
		en4=base64[c&0b111111];
		fputc(en1,fp2);
		fputc(en2,fp2);
		fputc(en3,fp2);
		fputc(en4,fp2);
	}
	fclose(fp);
	fclose(fp2);
}


int main(int argc, char *argv[])
{
	//D&D default:decode
	if(argc==2){
		b64decode(argv[1]);
		//b64encode(argv[1]);
		return 0;
	}
	puts("D&D default:decode");
	puts("decode:0");
	puts("encode:1");
	puts("format: filepath num");
	puts("example: C:\\test.txt 1");
	char fname[200];
	int f=0;
	scanf("%s %d",fname,&f);
	if(f==1)b64encode(fname);
	else b64decode(fname);
	return 0;
}