VC中BASE64编码和解码使用详解

2025-05-29 0 104

BASE64可以用来将binary的字节序列数据编码成ASCII字符序列构成的文本。完整的BASE64定义可见 RFC1421和 RFC2045。编码后的数据比原始数据略长,为原来的4/3。在电子邮件中,根据RFC822规定,每76个字符,还需要加上一个回车换行。

转换的时候,将三个byte的数据,先后放入一个24bit的缓冲区中,先来的byte占高位。数据不足3byte的话,于缓冲区中剩下的Bit用0补足。然后,每次取出6个bit,按照其值选择ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/中的字符作为编码后的输出。不断进行,直到全部输入数据转换完成。如果最后剩下两个输入数据,在编码结果后加1个“=”;如果最后剩下一个输入数据,编码结果后加2个“=”;如果没有剩下任何数据,就什么都不要加,这样才可以保证资料还原的正确性。

BASE64_API.h 文件内容

?

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

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

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69
/* ----------------------------------------------------------

文件名称:BASE64_API.h

作者:秦建辉

MSN:splashcn@msn.com

当前版本:V1.1

历史版本:

V1.1 2010年05月11日

修正BASE64解码的Bug。

V1.0 2010年05月07日

完成正式版本。

功能描述:

BASE64编码和解码

接口函数:

Base64_Encode

Base64_Decode

说明:

1. 参考openssl-1.0.0。

2. 改进接口,以使其适应TCHAR字符串。

3. 修正EVP_DecodeBlock函数解码时未去掉填充字节的缺陷。

------------------------------------------------------------ */

#pragma once

#include "stdafx.h"

#include <windows.h>

#ifdef __cplusplus

extern "C" {

#endif

/*

功能:将二进制数据转换成BASE64编码字符串

参数说明:

inputBuffer:要编码的二进制数据

inputCount:数据长度

outputBuffer:存储转换后的BASE64编码字符串

返回值:

-1:参数错误

>=0:有效编码长度(字符数),不包括字符串结束符。

备注:

等效于openssl中EVP_EncodeBlock函数

*/

INT BASE64_Encode( const BYTE* inputBuffer, INT inputCount, TCHAR* outputBuffer );

/*

功能:将BASE64编码字符串转换为二进制数据

参数说明:

inputBuffer:BASE64编码字符串

inputCount:编码长度(字符数),应该为4的倍数。

outputBuffer:存储转换后的二进制数据

返回值:

-1:参数错误

-2:数据错误

>=0:转换后的字节数

备注:

等效于openssl中EVP_DecodeBlock函数

*/

INT BASE64_Decode( const TCHAR* inputBuffer, INT inputCount, BYTE* outputBuffer );

#ifdef __cplusplus

}

#endif

BASE64_API.cpp 文件内容

?

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

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

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185
#pragma once

#include "stdafx.h"

#include "BASE64_API.h"

static const CHAR* DATA_BIN2ASCII = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

INT BASE64_Encode( const BYTE* inputBuffer, INT inputCount, TCHAR* outputBuffer )

{

INT i;

BYTE b0, b1, b2;

if( (inputBuffer == NULL) || (inputCount < 0) )

{

return -1; // 参数错误

}

if( outputBuffer != NULL )

{

for( i = inputCount; i > 0; i -= 3 )

{

if( i >= 3 )

{ // 将3字节数据转换成4个ASCII字符

b0 = *inputBuffer++;

b1 = *inputBuffer++;

b2 = *inputBuffer++;

*outputBuffer++ = DATA_BIN2ASCII[b0 >> 2];

*outputBuffer++ = DATA_BIN2ASCII[((b0 << 4) | (b1 >> 4)) & 0x3F];

*outputBuffer++ = DATA_BIN2ASCII[((b1 << 2) | (b2 >> 6)) & 0x3F];

*outputBuffer++ = DATA_BIN2ASCII[b2 & 0x3F];

}

else

{

b0 = *inputBuffer++;

if( i == 2 )b1 = *inputBuffer++; else b1 = 0;

*outputBuffer++ = DATA_BIN2ASCII[b0 >> 2];

*outputBuffer++ = DATA_BIN2ASCII[((b0 << 4) | (b1 >> 4)) & 0x3F];

*outputBuffer++ = (i == 1) ? TEXT('=') : DATA_BIN2ASCII[(b1 << 2) & 0x3F];

*outputBuffer++ = TEXT('=');

}

} // End for i

*outputBuffer++ = TEXT('/0'); // 添加字符串结束标记

}

return ((inputCount + 2) / 3) * 4; // 返回有效字符个数

}

#define B64_EOLN 0xF0 // 换行/n

#define B64_CR 0xF1 // 回车/r

#define B64_EOF 0xF2 // 连字符-

#define B64_WS 0xE0 // 跳格或者空格(/t、space)

#define B64_ERROR 0xFF // 错误字符

#define B64_NOT_BASE64(a) (((a)|0x13) == 0xF3)

static const BYTE DATA_ASCII2BIN[128] = {

0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xE0,0xF0,0xFF,0xFF,0xF1,0xFF,0xFF,

0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,

0xE0,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x3E,0xFF,0xF2,0xFF,0x3F,

0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0xFF,0xFF,0xFF,0x00,0xFF,0xFF,

0xFF,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,

0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0xFF,0xFF,0xFF,0xFF,0xFF,

0xFF,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,

0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0xFF,0xFF,0xFF,0xFF,0xFF

};

INT BASE64_Decode( const TCHAR* inputBuffer, INT inputCount, BYTE* outputBuffer )

{

INT i, j;

BYTE b[4];

TCHAR ch;

if( (inputBuffer == NULL) || (inputCount < 0) )

{

return -1; // 参数错误

}

// 去除头部空白字符

while( inputCount > 0 )

{

ch = *inputBuffer;

if( (ch < 0) || (ch >= 0x80) )

{

return -2; // 数据错误,不在ASCII字符编码范围内

}

else

{

if( DATA_ASCII2BIN[ch] == B64_WS )

{

inputBuffer++;

inputCount--;

}

else

{

break;

}

}

}

// 去除尾部的空白字符、回车换行字符、连字符

while( inputCount >= 4 )

{

ch = inputBuffer[inputCount - 1];

if( (ch < 0) || (ch >= 0x80) )

{

return -2; // 数据错误,不在ASCII字符编码范围内

}

else

{

if( B64_NOT_BASE64(DATA_ASCII2BIN[ch]) )

{

inputCount--;

}

else

{

break;

}

}

}

// 字符串长度必须为4的倍数

if( (inputCount % 4) != 0 )

{

return -2; // 数据错误

}

if( outputBuffer != NULL )

{

for( i = 0; i < inputCount; i += 4 )

{

for( j = 0; j < 4; j++ )

{

ch = *inputBuffer++;

if( (ch < 0) || (ch >= 0x80) )

{

return -2; // 数据错误,不在ASCII字符编码范围内

}

else

{

if( ch == '=' ) // 发现BASE64编码中的填充字符

{

break;

}

else

{

b[j] = DATA_ASCII2BIN[ch];

if( b[j] & 0x80 )

{

return -2; // 数据错误,无效的Base64编码字符

}

}

}

} // End for j

if( j == 4 )

{

*outputBuffer++ = (b[0] << 2) | (b[1] >> 4);

*outputBuffer++ = (b[1] << 4) | (b[2] >> 2 );

*outputBuffer++ = (b[2] << 6) | b[3];

}

else if( j == 3 )

{ // 有1个填充字节

*outputBuffer++ = (b[0] << 2) | (b[1] >> 4);

*outputBuffer++ = (b[1] << 4) | (b[2] >> 2 );

return (i >> 2) * 3 + 2;

}

else if( j == 2 )

{ // 有2个填充字节

*outputBuffer++ = (b[0] << 2) | (b[1] >> 4);

return (i >> 2) * 3 + 1;

}

else

{

return -2; // 数据错误,无效的Base64编码字符

}

} // End for i

}

return (inputCount >> 2) * 3;

}

采用以上方法就可以将二进制数据转换成可见字符进行传递就可以了.

那么如何使用呢?举以下两个例子

第一个:将一个图片转换成 txt 文本 并保存起来

?

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
//选择一个图像文件,将它转为 文本保存至 _T("D:\\\\2.txt"

void CTextPicDlg::OnBnClickedButton2()

{

// TODO: 在此添加控件通知处理程序代码

CFileDialog file(TRUE,".jpg","");

if (file.DoModal() == IDOK)

{

CFile data(file.GetPathName(), CFile::modeReadWrite);

int len = data.GetLength();

BYTE *dv;

dv = (BYTE *)malloc(len*sizeof(BYTE));

data.Read(dv, len);

data.Close();

int slen = (len / 3) * 4;

slen += 10;

TCHAR * tc;

tc = (TCHAR *)malloc(slen);

slen = BASE64_Encode(dv, len, tc);

CFile save(_T("D:\\\\2.txt"), CFile::modeCreate | CFile::modeWrite);

save.Write(tc, slen);

save.Close();

free(tc);

free(dv);

}

}

第二个例子,将一个文本文件还原为一个图像

?

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

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
void CTextPicDlg::OnBnClickedButton3()

{

// TODO: 在此添加控件通知处理程序代码

CFileDialog file(TRUE, ".txt", "");

if (file.DoModal() == IDOK)

{

CFile data(file.GetPathName(), CFile::modeReadWrite);

int len = data.GetLength();

TCHAR *dv;

dv = (TCHAR *)malloc(len*sizeof(TCHAR));

data.Read(dv, len);

data.Close();

int slen = (len / 4) * 3;

slen += 10;

BYTE * tc;

tc = (BYTE *)malloc(slen);

BASE64_Decode(dv, len, tc);

//直接在内存里面构建CIMAGE,需要使用IStream接口,如何使用

//构建内存环境

HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, slen);

void * pData = GlobalLock(hGlobal);

memcpy(pData, tc, slen); // 拷贝位图数据进去

GlobalUnlock(hGlobal);

// 创建IStream

IStream * pStream = NULL;

if (CreateStreamOnHGlobal(hGlobal, TRUE, &pStream) != S_OK)

return ;

// 使用CImage加载位图内存

CImage img;

if (SUCCEEDED(img.Load(pStream)) )

{

CClientDC dc(this);

//使用内在中构造的图像 直接在对话框上绘图

img.Draw(dc.m_hDC, 0, 0, 500, 300);

}

//释放内存

pStream->Release();

GlobalFree(hGlobal);

//如果要保存图像文件的话,那就使用下面的代码

//CFileDialog savefile(FALSE, ".jpg", "");

//if (savefile.DoModal()==IDOK)

//{

// CFile save(savefile.GetPathName(), CFile::modeCreate | CFile::modeWrite);

// save.Write(tc, slen);

// save.Close();

//}

free(tc);

free(dv);

}

}

至此,利用Base64转码的方式,来显示保存显示图片的方法,就算是成功了!

我们再来看一个base64编码解码的例子

首先是编码

?

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

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

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67
const BYTE Base64ValTab[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

#define AVal(x) Base64ValTab[x]

int CSeeBase64Dlg::EncodeBase64(char * pInput, char * pOutput)

{

int i = 0;

int loop = 0;

int remain = 0;

int iDstLen = 0;

int iSrcLen = (int)strlen(pInput);

loop = iSrcLen/3;

remain = iSrcLen%3;

// also can encode native char one by one as decode method

// but because all of char in native string is to be encoded so encode 3-chars one time is easier.

for (i=0; i < loop; i++)

{

BYTE a1 = (pInput[i*3] >> 2);

BYTE a2 = ( ((pInput[i*3] & 0x03) << 4) | (pInput[i*3+1] >> 4) );

BYTE a3 = ( ((pInput[i*3+1] & 0x0F) << 2) | ((pInput[i*3+2] & 0xC0) >> 6) );

BYTE a4 = (pInput[i*3+2] & 0x3F);

pOutput[i*4] = AVal(a1);

pOutput[i*4+1] = AVal(a2);

pOutput[i*4+2] = AVal(a3);

pOutput[i*4+3] = AVal(a4);

}

iDstLen = i*4;

if (remain == 1)

{

// should pad two equal sign

i = iSrcLen-1;

BYTE a1 = (pInput[i] >> 2);

BYTE a2 = ((pInput[i] & 0x03) << 4);

pOutput[iDstLen++] = AVal(a1);

pOutput[iDstLen++] = AVal(a2);

pOutput[iDstLen++] = '=';

pOutput[iDstLen++] = '=';

pOutput[iDstLen] = 0x00;

}

else if (remain == 2)

{

// should pad one equal sign

i = iSrcLen-2;

BYTE a1 = (pInput[i] >> 2);

BYTE a2 = ( ((pInput[i] & 0x03) << 4) | (pInput[i+1] >> 4));

BYTE a3 = ( (pInput[i+1] & 0x0F) << 2);

pOutput[iDstLen++] = AVal(a1);

pOutput[iDstLen++] = AVal(a2);

pOutput[iDstLen++] = AVal(a3);

pOutput[iDstLen++] = '=';

pOutput[iDstLen] = 0x00;

}

else

{

// just division by 3

pOutput[iDstLen] = 0x00;

}

return iDstLen;

}

下面是解码

?

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

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

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66
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 CSeeBase64Dlg::DecodeBase64(char * pInput, char * pOutput)

{

int i = 0;

int iCnt = 0;

int iSrcLen = (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;

}

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 VC中BASE64编码和解码使用详解 https://www.kuaiidc.com/106916.html

相关文章

发表评论
暂无评论