Chinaunix

标题: 请教关于二进制转BASE64的问题 [打印本页]

作者: wanglei051    时间: 2007-01-29 16:41
标题: 请教关于二进制转BASE64的问题
我需要将二进制文件数据转成BASE64,然后存入xml的CDATA中发送到server,但网上找了好几个例子都不能很完全得转码,而直接把二进制数据放入CDATA里,会无法解析,提示有无效字符,谁知道如何解决,还望赐教。
我在libxml2中找到2个函数,xmlTextWriterWriteBase64和xmlTextWriterWriteBinHex,但好像作用不大,也许是我调用得方法不对吧
作者: upstorm    时间: 2007-01-29 17:07
xml本身就是文本协议,如果有非文本的数据当然不行
二进制文件数据转成BASE64自己写个函数就行了,不用找现成的
如果你一定要找的话,哎........................................................
#ifndef _BASE64_H_
#define _BASE64_H_

//#include "basicinc.h"

#include <conf.h>
class CBase64Coder
{
private :
        static char ch64[];
        char* buf;
        int size ;

private :
        static int BinSearch(char p);
        void allocMem(int NewSize);

public :
        CBase64Coder();
        ~CBase64Coder();
        const char* encode(const string& message);
        const char* encode(const char* buffer,int buflen);
        const char* decode(const char* buffer,int Length);

};

#endif

#include "CBase64.h"

char CBase64Coder::ch64[] = {
'A','B','C','D','E','F','G','H','I','J','K','L','M','N',
'O','P','Q','R','S','T','U','V','W','X','Y','Z',
'a','b','c','d','e','f','g','h','i','j','k','l','m','n',
'o','p','q','r','s','t','u','v','w','x','y','z',
'0','1','2','3','4','5','6','7','8','9','+','/','='
};

CBase64Coder::CBase64Coder()
{
        buf = NULL;
        size = 0 ;
}

CBase64Coder::~CBase64Coder()
{
        if ( buf )
                free(buf);
}

void CBase64Coder::allocMem(int NewSize)
{
        if ( buf )
                buf = (char*)realloc(buf,NewSize);
        else
                buf = (char*)malloc(NewSize);
        memset(buf,0,NewSize);
}

const  char* CBase64Coder::encode(const string& buffer)
{
        return encode(buffer.c_str(),buffer.length());
}

const char* CBase64Coder::encode(const char* buffer,int buflen)
{
        int nLeft =  3 - buflen%3 ;
        //根据BASE64算法,总长度会变成原来的4/3倍
        //所以内存分配=length*4/3并加1位作为结束符号(0)
        allocMem(( buflen + nLeft )*4/3+1);
        //临时变量,
        char ch[4];
        int i ,j;
        for ( i = 0 ,j = 0; i < ( buflen - buflen%3 );  i += 3,j+= 4 )
        {
                ch[0] = (char)((buffer[i]&0xFC) >> 2 );
                ch[1] = (char)((buffer[i]&0x03) << 4 | (buffer[i+1]&0xF0) >> 4 );
                ch[2] = (char)((buffer[i+1]&0x0F) << 2 | (buffer[i+2]&0xC0) >> 6 );
                ch[3] = (char)((buffer[i+2]&0x3F));
                //查询编码数组获取编码后的字符
                buf[j] = ch64[ch[0]];
                buf[j+1] = ch64[ch[1]];
                buf[j+2] = ch64[ch[2]];
                buf[j+3] = ch64[ch[3]];
        }
       
        if ( nLeft == 2 )
        {
                ch[0] = (char)((buffer[i]&0xFC) >> 2);
                ch[1] = (char)((buffer[i]&0x3) << 4 );
                ch[2] = 64;
                ch[3] = 64;

                //查询编码数组获取编码后的字符
                buf[j] = ch64[ch[0]];
                buf[j+1] = ch64[ch[1]];
                buf[j+2] = ch64[ch[2]];
                buf[j+3] = ch64[ch[3]];
        }
        else if ( nLeft == 1 )
        {
                ch[0] = (char)((buffer[i]&0xFC) >> 2 );
                ch[1] = (char)((buffer[i]&0x03) << 4 | (buffer[i+1]&0xF0) >> 4 );
                ch[2] = (char)((buffer[i+1]&0x0F) << 2 );
                ch[3] = 64;

                //查询编码数组获取编码后的字符
                buf[j] = ch64[ch[0]];
                buf[j+1] = ch64[ch[1]];
                buf[j+2] = ch64[ch[2]];
                buf[j+3] = ch64[ch[3]];
        }
        return buf;
}

const char* CBase64Coder::decode(const char* buffer,int Length)
{
        int length = Length;
        if ( length%4 != 0 )
                return NULL;

        allocMem(length*3/4 + 1);

        char p;
        char ch[4];
        int i , j ;
        for ( i = 0 , j = 0 ; i < length ; i += 4 , j+= 3)
        {
                for ( int z = 0 ; z < 4 ; z++)
                {
                        //采用2分法查找
                        p = (char)BinSearch(buffer[i+z]);
                        if ( p == -1 )
                                return NULL;
                        ch[z] = p;
                }

                buf[j] = (char)((ch[0]&0x3F) << 2 | (ch[1]&0x30) >> 4 );
                buf[j+1] = (char)((ch[1]&0xF) <<4 | (ch[2]&0x3C) >>2 );
                buf[j+2] = (char)((ch[2]&0x03) << 6 | (ch[3]&0x3F));
        }
        return buf;
}

//采用二分法查找p在ch64数组中的位置,并返回。如果找不到则返回-1
int CBase64Coder::BinSearch(char p)
{
        if ( p >= 'A' && p <= 'Z' )
                return (p - 'A');
        else if ( p >= 'a' && p <= 'z' )
                return (p - 'a' + 26);
        else if ( p >= '0' && p <= '9' )
                return (p - '0' + 26 + 26);
        else if ( p == '+' )
                return 62;
        else if ( p == '/' )
                return 63;
        else if ( p == '=' )
                return 64;
        return -1;
}
作者: langue    时间: 2007-01-29 17:09
--

二进制转 base64,可以看成是把 256 进制的数转成 64 进制的,这样就好理解了吧。

--
作者: wanglei051    时间: 2007-01-29 17:24
我在看看,其实也想自己写一个编码解码规则,但一时没有思路,如果不是因为通讯协议是基于xml的,我直接传可执行程序就行了,所以找了好多转码的例子都不成功,我先试试,谢谢两位!
作者: upstorm    时间: 2007-01-29 17:25
原帖由 langue 于 2007-1-29 17:09 发表
--

二进制转 base64,可以看成是把 256 进制的数转成 64 进制的,这样就好理解了吧。

--


准确的讲,是64个字符
作者: langue    时间: 2007-01-29 17:33
原帖由 upstorm 于 2007-1-29 17:25 发表


准确的讲,是64个字符


额,进制里的每一位上允许使用的 “数”,可以是 ASCII 码集合里的元素,也可以是其他任意的元素。个人意见。

用字符显然直观。

ln(256)/ln(64) = 4/3

所以通常二进制数据转换成 base64 后长度会增大,增大的幅度为原来的 1/3 左右。数据越长,就越接近这个值。

--
作者: wanglei051    时间: 2007-01-30 09:36
昨天测试了,结果还是转了一段后全是A了,可能是后面的没有转成功吧,也许有字符不能转吧
f0VMRgEBAVKhLJUECIP4/7sslQQIdAyD6wT/0IsDg/j/dfRYW8nDVYnlU+g3b25fc3RhcnRvbl9zdGFydAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
作者: yulc    时间: 2007-01-30 11:51
原帖由 wanglei051 于 2007-1-29 16:41 发表
我需要将二进制文件数据转成BASE64,然后存入xml的CDATA中发送到server,但网上找了好几个例子都不能很完全得转码,而直接把二进制数据放入CDATA里,会无法解析,提示有无效字符,谁知道如何解决,还望赐教。
我 ...



楼主, 我的签名有你要的东西... 哈哈
作者: wanglei051    时间: 2007-01-30 13:05
我简直太崇拜你了!不过我纳闷,有上传限制的话分卷不就行了,还要加密压缩:(
作者: wanglei051    时间: 2007-01-30 13:12
看来我还是有点懒,你的代码和2楼的差不多,只需要稍微加几行,可惜没怎么调试。
顺便夸你一下,用自己的东东给自己的代码加密,还真会想:)
作者: langue    时间: 2007-01-30 16:46
原帖由 wanglei051 于 2007-1-30 09:36 发表
昨天测试了,结果还是转了一段后全是A了,可能是后面的没有转成功吧,也许有字符不能转吧
f0VMRgEBAVKhLJUECIP4/7sslQQIdAyD6wT/0IsDg/j/dfRYW8nDVYnlU+g3b25fc3RhcnRvbl9zdGFydAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA ...


全是 A,不是代表零字节么?

--
作者: wanglei051    时间: 2007-01-31 15:12
问题是文件5K大小呢,怎么可能这么点呢,不过最后解决了,是我犯了个小错误,唉!
谢谢几位,做了2年的linux编程,还是这么马虎!
作者: langue    时间: 2007-01-31 17:18
原帖由 wanglei051 于 2007-1-31 15:12 发表
问题是文件5K大小呢,怎么可能这么点呢,不过最后解决了,是我犯了个小错误,唉!
谢谢几位,做了2年的linux编程,还是这么马虎!


有机会多看看 K&R。无论是看过还是没看过,你一定能得到新的启发。权当作是复习吧。

--




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2