wu

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

遇到一个问题:要将一个指定长度的char数组的图片数据通过网络传输,但是所使用的网络数据协议是字符类型的。所以char图片数组里有可能含有\0等字符,会影响到数据的解码。这是就用到了Base64算法。

先来看一下Base64的介绍(http://zh.wikipedia.org/wiki/Base64)
在MIME格式的电子邮件中,base64可以用来将binary的字节序列数据编码成ASCII字符序列构成的文本。使用时,在传输编码方式中指定base64。使用的字符包括大小写字母各26个,加上10个数字,和加号“+”,斜杠“/”,一共64个字符,等号“=”用来作为后缀用途。完整的base64定义可见 RFC 1421和 RFC 2045。编码后的数据比原始数据略长,为原来的4/3。在电子邮件中,根据RFC 822规定,每76个字符,还需要加上一个回车换行。可以估算编码后数据长度大约为原长的135.1%。
转换的时候,将三个byte的数据,先后放入一个24bit的缓冲区中,先来的byte占高位。数据不足3byte的话,于缓冲区中剩下的bit用0补足。然后,每次取出6(因为26 = 64)个bit,按照其值选择ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/中的字符作为编码后的输出。不断进行,直到全部输入数据转换完成。
下面是一个简单的实现:

union
{
    struct
    {
        unsigned long d: 6;
        unsigned long c: 6;
        unsigned long b: 6;
        unsigned long a: 6;
    } s;
    unsigned char  uch[3];
} stUnit;

char* strBase = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

int MyEncodeBase64(const char *pInput, const int iInputLen, char *pOutput)
{
    int iCur = 0;
    int iOutputLen = 0;
    int n = 0;

    while (1)
    {
        stUnit.uch[0] = stUnit.uch[1] = stUnit.uch[2] = 0;

        for (n = 0; n < 3; n++)
        {
            if (iInputLen == iCur)
            {
                break;
            }

            stUnit.uch[2 - n] = (unsigned char)pInput[iCur++];
        }

        if (n == 0)
        {
            break;
        }

        switch (n)
        {
            case 1:
                pOutput[iOutputLen++] =  strBase[stUnit.s.a];
                pOutput[iOutputLen++] =  strBase[stUnit.s.b];
                pOutput[iOutputLen++] =  '=';
                pOutput[iOutputLen++] =  '=';
                break;

            case 2:
                pOutput[iOutputLen++] =  strBase[stUnit.s.a];
                pOutput[iOutputLen++] =  strBase[stUnit.s.b];
                pOutput[iOutputLen++] =  strBase[stUnit.s.c];
                pOutput[iOutputLen++] =  '=';
                break;

            case 3:
                pOutput[iOutputLen++] =  strBase[stUnit.s.a];
                pOutput[iOutputLen++] =  strBase[stUnit.s.b];
                pOutput[iOutputLen++] =  strBase[stUnit.s.c];
                pOutput[iOutputLen++] =  strBase[stUnit.s.d];
                break;
        }
    }

    return iOutputLen;
}

//下面是解析的:
const BYTE Base64IdxTab[128] =
{
    255, 255, 255, 255,  255, 255, 255, 255,  255, 255, 255, 255,  255, 255, 255, 255,
    255, 255, 255, 255,  255, 255, 255, 255,  255, 255, 255, 255,  255, 255, 255, 255,
    255, 255, 255, 255,  255, 255, 255, 255,  255, 255, 255, 62,   255, 255, 255, 63,
    52, 53, 54, 55,      56, 57, 58, 59,      60, 61, 255, 255,    255, 255, 255, 255,
    255, 0, 1, 2,        3, 4, 5, 6,          7, 8, 9, 10,         11, 12, 13, 14,
    15, 16, 17, 18,      19, 20, 21, 22,      23, 24, 25, 255,     255, 255, 255, 255,
    255, 26, 27, 28,     29, 30, 31, 32,      33, 34, 35, 36,      37, 38, 39, 40,
    41, 42, 43, 44,      45, 46, 47, 48,      49, 50, 51, 255,     255, 255, 255, 255
};
#define BVal(x) Base64IdxTab[x]

int DecodeBase64(char *pInput, const int iInputLen, char *pOutput)
{
    int i = 0;
    int iCnt = 0;
    int iSrcLen = iInputLen; //(int)strlen(pInput);

    char *p = pOutput;

    for (i = 0; i < iSrcLen; i++)
    {
        if (pInput[i] > 127)
        {
            continue;
        }

        if (pInput[i] == '=')
        {
            return p - pOutput + 1;
        }

        BYTE a = BVal(pInput[i]);

        if (a == 255)
        {
            continue;
        }

        switch (iCnt)
        {
            case 0:
            {
                *p = a << 2;
                iCnt++;
            }
            break;

            case 1:
            {
                *p++ |= a >> 4;
                *p = a << 4;
                iCnt++;
            }
            break;

            case 2:
            {
                *p++ |= a >> 2;
                *p = a << 6;
                iCnt++;
            }
            break;

            case 3:
            {
                *p++ |= a;
                iCnt = 0;
            }
            break;
        }
    }

    *p = 0x00;
    return p - pOutput;
}
    char buffer[256 * 1024] = {0};

    FILE *pFile;
    long lSize;
    size_t result;

    pFile = fopen ("a.jpg" , "r" );

    // obtain file size:
    fseek (pFile , 0 , SEEK_END);
    lSize = ftell (pFile);
    rewind (pFile);

    result = fread (buffer, 1, lSize, pFile);
    fclose(pFile);

    printf("PicSize:%d.\n", result);

    char pOutputBuff[256 * 1024 * 2] = {0};
    int iOutLen = 0;
    iOutLen = MyEncodeBase64(buffer, lSize, pOutputBuff);
    ///
    printf("\nEncdoeLen %d.\n", iOutLen);
    //fwrite
    char pic_file_name[255];
    snprintf(pic_file_name, 255, "./encode%03u.txt", 1);
    FILE *fp = fopen(pic_file_name, "w");
    fwrite(pOutputBuff, iOutLen, 1, fp);
    fclose(fp);


    //Decode
    char pDecodeBuff[256 * 1024 * 2] = {0};
    int iLen = DecodeBase64(pOutputBuff, iOutLen, pDecodeBuff);
    printf("\ndecode len %d.\n", iLen);

    snprintf(pic_file_name, 255, "./decode%03u.jpg", 2);
    FILE *fp2 = fopen(pic_file_name, "w");
    fwrite(pDecodeBuff, iLen, 1, fp2);
    fclose(fp2);



posted on 2011-12-21 14:06  butterflydog  阅读(227)  评论(0编辑  收藏  举报