C语言实现Base64编码转码

C语言实现Base64编码转码

关于Base64的介绍有两篇文章已经做得非常好了:一篇是维基百科Base64的词条,如果被Q可以看本文👇摘录维基百科Base64;另一篇是阮一峰的Base64笔记

说一说C语言的实现吧,其实维基百科给出了C语言的实现了,但是它用以处理File,当然原理都是一样的,File的处理其实可以放在外面做好.

另外,根据Base64介绍可以看出来它以6比特为一个单元,而常规1字节为8比特,所以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

static const char *ALPHA_BASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

 

char *encode(const char *buf, const long size, char *base64Char) {

    int a = 0;

    int i = 0;

    while (i < size) {

        char b0 = buf[i++];

        char b1 = (i < size) ? buf[i++] : 0;

        char b2 = (i < size) ? buf[i++] : 0;

         

        int int63 = 0x3F; //  00111111

        int int255 = 0xFF; // 11111111

        base64Char[a++] = ALPHA_BASE[(b0 >> 2) & int63];

        base64Char[a++] = ALPHA_BASE[((b0 << 4) | ((b1 & int255) >> 4)) & int63];

        base64Char[a++] = ALPHA_BASE[((b1 << 2) | ((b2 & int255) >> 6)) & int63];

        base64Char[a++] = ALPHA_BASE[b2 & int63];

    }

    switch (size % 3) {

        case 1:

            base64Char[--a] = '=';

        case 2:

            base64Char[--a] = '=';

    }

    return base64Char;

}

 

char *decode(const char *base64Char, const long base64CharSize, char *originChar, long originCharSize) {

    int toInt[128] = {-1};

    for (int i = 0; i < 64; i++) {

        toInt[ALPHA_BASE[i]] = i;

    }

    int int255 = 0xFF;

    int index = 0;

    for (int i = 0; i < base64CharSize; i += 4) {

        int c0 = toInt[base64Char[i]];

        int c1 = toInt[base64Char[i + 1]];

        originChar[index++] = (((c0 << 2) | (c1 >> 4)) & int255);

        if (index >= originCharSize) {

            return originChar;

        }

        int c2 = toInt[base64Char[i + 2]];

        originChar[index++] = (((c1 << 4) | (c2 >> 2)) & int255);

        if (index >= originCharSize) {

            return originChar;

        }

        int c3 = toInt[base64Char[i + 3]];

        originChar[index++] = (((c2 << 6) | c3) & int255);

    }

    return originChar;

}

在调用的时候一定要注意malloc的大小.

这个Base64其实我们经常在用,只是没有留意而已.比如P2P下载工具*雷就用Base64编码了很多资源,我这里找了一个电影<独立日:卷土重来.BD1280高清国英双语特效中英双字>下载链接是这样的: thu*der://QUFlZDJrOi8vfGZpbGV8JUU3JThCJUFDJUU3JUFCJThCJUU2JTk3JUE1JUVGJUJDJTlBJUU1JThEJUI3JUU1JTlDJTlGJUU5JTg3JThEJUU2JTlEJUE1LkJEMTI4MCVFOSVBQiU5OCVFNiVCOCU4NSVFNSU5QiVCRCVFOCU4QiVCMSVFNSU4RiU4QyVFOCVBRiVBRCVFNyU4OSVCOSVFNiU5NSU4OCVFNCVCOCVBRCVFOCU4QiVCMSVFNSU4RiU4QyVFNSVBRCU5Ny5tcDR8MTY4MzQwNTM1NXxGRjRGNDc2MzE4REVEMzg3MEQxRkJGNENCOTU5MEE0NHxoPTdFU1BGTEpKQ1ZZWkE3UUU0R0JERkpOVUozU1pWRDNZfC9aWg== 看似挺聪明的做法,自定义了协议头,后面一大串晕晕乎乎的不知道是什么东西,一般的资源都是带文件名至少能看到后缀名啥的,不过看到最后又两个 '=' 字符,这个就很明显是这边文章的主题Base64,在看这里面的字符都在Base64定义的字符内 就可以认定这个是Base64编码后的链接.如果你恰好没装*雷,也不想装*雷(这货会偷偷上传文件,别问我怎么知道的,亲手抓到的),就可以把协议头后面的一大串字符串拷贝出来,decode一下可以得到 AAed2k://|file|%E7%8B%AC%E7%AB%8B%E6%97%A5%EF%BC%9A%E5%8D%B7%E5%9C%9F%E9%87%8D%E6%9D%A5.BD1280%E9%AB%98%E6%B8%85%E5%9B%BD%E8%8B%B1%E5%8F%8C%E8%AF%AD%E7%89%B9%E6%95%88%E4%B8%AD%E8%8B%B1%E5%8F%8C%E5%AD%97.mp4|1683405355|FF4F476318DED3870D1FBF4CB9590A44|h=7ESPFLJJCVYZA7QE4GBDFJNUJ3SZVD3Y|/ZZ 去掉 AA 剩下 ed2k://|file|%E7%8B%AC%E7%AB%8B%E6%97%A5%EF%BC%9A%E5%8D%B7%E5%9C%9F%E9%87%8D%E6%9D%A5.BD1280%E9%AB%98%E6%B8%85%E5%9B%BD%E8%8B%B1%E5%8F%8C%E8%AF%AD%E7%89%B9%E6%95%88%E4%B8%AD%E8%8B%B1%E5%8F%8C%E5%AD%97.mp4|1683405355|FF4F476318DED3870D1FBF4CB9590A44|h=7ESPFLJJCVYZA7QE4GBDFJNUJ3SZVD3Y|/ZZ 这下认得了吧.用想用的下载工具下载吧.当然也可以用在线的base64 转码工具.

 

 

以下内容摘自维基百科

Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2的6次方等于64,所以每6个比特为一个单元,对应某个可打印字符。三个字节有24个比特,对应于4个Base64单元,即3个字节需要用4个可打印字符来表示。它可用来作为电子邮件的传输编码。在Base64中的可打印字符包括字母A-Z、a-z、数字0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。一些如uuencode的其他编码方法,和之后binhex的版本使用不同的64字符集来代表6个二进制数字,但是它们不叫Base64。

Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据。包括MIME的email、在XML中存储复杂数据。

目录

 [隐藏

 

MIME[编辑]

MIME格式的电子邮件中,base64可以用来将binary的字节序列数据编码成ASCII字符序列构成的文本。使用时,在传输编码方式中指定base64。使用的字符包括大小写字母各26个,加上10个数字,和加号“+”,斜杠“/”,一共64个字符,等号“=”用来作为后缀用途。

完整的base64定义可见RFC 1421和RFC 2045。编码后的数据比原始数据略长,为原来的43。在电子邮件中,根据RFC 822规定,每76个字符,还需要加上一个回车换行。可以估算编码后数据长度大约为原长的135.1%。

转换的时候,将三个byte的数据,先后放入一个24bit的缓冲区中,先来的byte占高位。数据不足3byte的话,于缓冲器中剩下的bit用0补足。然后,每次取出6(因为26=64)个bit,按照其值选择ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/中的字符作为编码后的输出。不断进行,直到全部输入数据转换完成。

当原数据长度不是3的整数倍时, 如果最后剩下一个输入数据,在编码结果后加2个“=”;如果最后剩下两个输入数据,编码结果后加1个“=”;如果没有剩下任何数据,就什么都不要加,这样才可以保证数据还原的正确性。

  • 编码“Man”
文本Man
ASCII编码7797110
二进制位010011010110000101101110
索引1922546
Base64编码TWFu

在此例中,Base64算法将三个字符编码为4个字符

Base64索引表:

数值字符 数值字符 数值字符 数值字符
0A16Q32g48w
1B17R33h49x
2C18S34i50y
3D19T35j51z
4E20U36k520
5F21V37l531
6G22W38m542
7H23X39n553
8I24Y40o564
9J25Z41p575
10K26a42q586
11L27b43r597
12M28c44s608
13N29d45t619
14O30e46u62+
15P31f47v63/

如果要编码的字节数不能被3整除,最后会多出1个或2个字节,那么可以使用下面的方法进行处理:先使用0字节值在末尾补足,使其能够被3整除,然后再进行base64的编码。在编码后的base64文本后加上一个或两个'='号,代表补足的字节数。也就是说,当最后剩余一个八位字节(一个byte)时,最后一个6位的base64字节块有四位是0值,最后附加上两个等号;如果最后剩余两个八位字节(2个byte)时,最后一个6位的base字节块有两位是0值,最后附加一个等号。 参考下表:

文本(1 Byte)A  
二进制位01000001                
二进制位(补0)010000010000            
Base64编码QQ  
文本(2 Byte)BC 
二进制位0100001001000011  xxxxxx
二进制位(补0)010000100100001100xxxxxx
Base64编码QkM 

UTF-7[编辑]

UTF-7是一个修改的Base64(Modified Base64)。主要是将UTF-16的数据,用Base64的方法编码为可打印的ASCII字符序列。目的是传输Unicode数据。主要的区别在于不用等号"="补余,因为该字符通常需要大量的转译。

标准可见RFC 2152,《A Mail-Safe Transformation Format of Unicode》。

IRCu[编辑]

IRCu等软件所使用的P10 IRC服务器间协议中,对客户与服务器的消息类型号(client/server numerics)和二进制IP地址采用了base64编码。消息类型号的长度固定为3字节,故可直接编码为4个字节而不需要加填充。对IP地址进行编码时,则需要在地址前添加一些0比特,使之可以编码为整数个字节。这里所用的符号集与前述MIME的也有所不同,将+/改成了[]。

在URL中的应用[编辑]

Base64编码可用于在HTTP环境下传递较长的标识信息。例如,在Java持久化系统Hibernate中,就采用了Base64来将一个较长的唯一标识符(一般为128-bit的UUID)编码为一个字符串,用作HTTP表单和HTTP GET URL中的参数。在其他应用程序中,也常常需要把二进制数据编码为适合放在URL(包括隐藏表单域)中的形式。此时,采用Base64编码不仅比较简短,同时也具有不可读性,即所编码的数据不会被人用肉眼所直接看到。

然而,标准的Base64并不适合直接放在URL里传输,因为URL编码器会把标准Base64中的“/”和“+”字符变为形如“%XX”的形式,而这些“%”号在存入数据库时还需要再进行转换,因为ANSI SQL中已将“%”号用作通配符。

为解决此问题,可采用一种用于URL的改进Base64编码,它不在末尾填充'='号,并将标准Base64中的“+”和“/”分别改成了“-”和“_”,这样就免去了在URL编解码和数据库存储时所要作的转换,避免了编码信息长度在此过程中的增加,并统一了数据库、表单等处对象标识符的格式。

另有一种用于正则表达式的改进Base64变种,它将“+”和“/”改成了“!”和“-”,因为“+”,“*”以及前面在IRCu中用到的“[”和“]”在正则表达式中都可能具有特殊含义。

此外还有一些变种,它们将“+/”改为“_-”或“._”(用作编程语言中的标识符名称)或“.-”(用于XML中的Nmtoken)甚至“_:”(用于XML中的Name)。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值