1、背景:数据在网络中传输是以二进制的形式传输,如果数据是英文,则传输不会出现乱码的情况。如果是中文,不同环境下的编码方式可能造成乱码的现象发生。
2、作用:能够将二进制文件、图片等转换成可见的字符,用于传输,确保图片数据不会丢失。
3、实现步骤:
- 将待转换的字符串每三个字节分为一组,每个字节占8bit,那么共有24个二进制位。
- 将上面的24个二进制位每6个一组,共分为4组。
- 在每组前面添加两个0,每组由6个变为8个二进制位,总共32个二进制位,即四个字节。
- 根据Base64编码对照表(见下图)获得对应的值。
['A', 'B', 'C', ... 'a', 'b', 'c', ... '0', '1', ... '+', '/']
中文有多个编码方式(UTF-8,GB-2312,GBK…),每种编码方式对应出来的二进制数都不相同,所以base64编码不同。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ERROR_INVALID_ARG -1
#define ERROR_INVALID_OP -2
#define ERROR_INVALID_SYN -3
#define ERROR_OPEN_FILE -4
#define OPERATION_SUCCESS 0
const char base64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
FILE *input, *output;
int encode64(FILE *input_file, FILE* output_file);
int decode64(FILE *input_file, FILE* output_file);
int main(int argc, char* argv[]){
int state;
//Check arguments
if(argc != 4)
{
printf("Error: Invalid Argument\n");
return ERROR_INVALID_ARG;
}
//Open File to Read
input = fopen(argv[2],"rb");
if(!input)
{
printf("Error: Unable to open source\n");
return ERROR_OPEN_FILE;
}
//Check for operation
if(!strcmp(argv[1],"encode"))
{
output = fopen(argv[3],"w");
state = encode64(input,output);
}
else if(!strcmp(argv[1],"decode"))
{
output = fopen(argv[3],"wb");
state = decode64(input,output);
}
else
{
printf("Error: Invalid Operation\n");
return ERROR_INVALID_OP;
}
//Print Results
if(state)
{
printf("Error: Source contains invalid character\n");
}
else
{
printf("Successfully Encode/Decode Items\n");
}
fclose(input);
fclose(output);
return state;
}
int encode64(FILE* input_file, FILE* output_file)
{
//Variables Declaration
int decode_buffer = 0;
int byteCount = 1;
int temp;
char raw_byte = 0;
char out_byte = 0;
//Read and encode
while(fread(&raw_byte,sizeof(char),1,input_file)) // 每次读取一个字节
{
temp = raw_byte & ~(-1<<8);
decode_buffer = (decode_buffer << 8) + temp;
if(byteCount % 3 == 0)
{ //Every 3 byte -> 4 base64 char
for(temp = 0; temp < 4; temp++)
{
out_byte = base64_table[(decode_buffer>>(6*(3-temp)) & 0b00111111)];
fprintf(output_file,"%c",out_byte);
}
decode_buffer = 0;
}
byteCount ++;
}
if(byteCount % 3)
{ //If padding is needed
for(temp = 0;temp < byteCount %3; temp++)
decode_buffer = (decode_buffer << 8) ; //Fill the missing 1 or 2 byte
for(temp = 0; temp < 4-(byteCount%3); temp++)
{ //If fill 1 byte -> Get 3 char; if fill 2 byte -> get 2 char => 4-fill_no
out_byte = base64_table[(decode_buffer>>(6*(3-temp)) & 0b00111111)];
fprintf(output_file,"%c",out_byte);
}
for(temp = 0;temp < byteCount %3; temp++)
fprintf(output_file,"=");
}
return OPERATION_SUCCESS;
}
int decode64(FILE* input_file, FILE* output_file)
{
int decode_buffer = 0;
int byteCount = 1;
int paddingCount = 0;
int i;
char raw_byte=0;
char resolved_byte = 0;
unsigned char temp;
//Read and decode
while(fread(&raw_byte,sizeof(char),1,input_file))
{
if(raw_byte == '='){ //If a padding is encountered
raw_byte = 'A'; //Turn it into 0
paddingCount ++;
}
//Decode the character
char* pt = strchr(base64_table,(unsigned char)raw_byte);
if(!pt)
{//Unable to resolve character
return ERROR_INVALID_SYN;
}
resolved_byte = pt-base64_table;
resolved_byte = resolved_byte & ~(-1<<6); //Mask the byte to ensure all the bit except the last 6 is zero
decode_buffer = (decode_buffer<<6) + resolved_byte;
if(byteCount%4 == 0)
{ //Every 4 base64 char -> 3 byte
for(i=0;i<3-paddingCount;i++)
{
temp = (decode_buffer>>(8*(2-i))) & ~(-1<<8);
fwrite(&temp,sizeof(char),1,output_file);
}
decode_buffer = 0;
}
byteCount++;
}
return O