BASE64

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