5

我正在阅读这个libb64源代码,用于编码和解码 base64 数据。

我知道编码过程,但我不知道如何构建以下解码表以进行快速查找以执行编码的 base64 字符的解码。这是他们正在使用的表格:

static const char decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,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,-1,-1,-1,-1,-1,-1,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};

有人能解释一下这个表中的值如何用于解码目的吗?

4

3 回答 3

6

这是一个移位和有限的 ASCII 转换表。表的键是 ASCII 值,值是 base64 解码值。该表被移动,使得索引0实际上映射到 ASCII 字符+,并且任何进一步的索引都映射 ASCII 值之后+。表中的第一个条目,即 ASCII 字符+,映射到 base64 值62。然后忽略三个字符 (ASCII ,-.) 并将下一个字符映射到 base64 值63。下一个字符是 ASCII /

如果您查看该表和ASCII 表,其余部分将变得显而易见。

它的用法是这样的:

int decode_base64(char ch) {
    if (ch < `+` or ch > `z`) {
        return SOME_INVALID_CH_ERROR;
    }

    /* shift range into decoding table range */
    ch -= `+`;

    int base64_val = decoding[ch];

    if (base64_val < 0) {
        return SOME_INVALID_CH_ERROR;
    }

    return base64_val;
}
于 2012-07-19T10:57:16.277 回答
5

众所周知,每个字节有 8 位,可能有 256 种组合与 2 个符号(base2)。
使用 2 个符号需要浪费 8 个字符来表示一个字节,例如 '01010011'。
使用基数 64 可以用 1 个字符表示 64 种组合...
所以,我们有一个基表:
A = 000000
B = 000001
C = 000010
...
如果你有“Man”这个词,那么你就有了字节:
01001101、01100001、01101110等

01101010110000101101110

六位组中断:010011 010110 000101
10111010011010011010011 = T
010110 = W 000101 = W 000101
= F 101110 = f 101110 = f
101110 = u
so,'so,'Man'= base64'=> Base64'=> base64'='Twfu'。
正如所见,这对于长度为 6 的倍数的流非常有效。

如果您的流不是 6 的倍数,例如“Ma”,则您有以下流:
010011 010110 0001
您需要完成才能拥有 6 组:
010011 010110 000100
,因此您拥有编码基数 64:
010011 = T
010110 = W
000100 = E
所以,'Ma' => 'TWE'

在解码流之后,在这种情况下,您需要将最后的倍数长度计算为 8 的倍数,因此删除额外的位以获得原始流:
T = 010011
W = 010110
E = 000100
1) 010011 010110 000100
2) 01001101 01100001 00
3) 01001101 01100001 = '马'
实际上,当我们放置尾随 00 时,我们用 '=' 标记 Base64 字符串的结尾添加到每个尾随 '00('Ma' ==> Base64 'TWE=')


参见链接:http://www .base64decode.org/


在 base 64 上表示的图像是一个很好的选择,可以在许多应用程序中用字符串表示,因为这些应用程序很难直接使用真正的二进制流。真正的二进制流更好,因为它是 base256,但在 HTML 中很难,例如,有 2 种方式,较小的流量,或者更容易使用字符串。

参见 ASCII 代码,base 64 的字符在表 ASCII 上从范围 '+' 到 'z' 但在 '+' 和 'z' 之间有一些值不是 base 64 符号


'+' = ASCII DEC 43
...
'z' = ASCII DEC 122
从 DEC 43 到 122 是 80 个值,但
43 OK = '+'
44 不是 base 64 符号,因此解码索引为 -1(base64 的无效符号)
45 ... .
46 ...
...
122 OK = 'z'
执行解码所需的字符,将 43 ('+') 递减为向量上的索引 0,以便通过索引快速访问,因此,解码 [80] = {62, -1, -1 ........, 49, 50,51};


Roberto Novakosky
开发者系统

于 2013-06-15T03:33:03.787 回答
0

考虑这两个映射表:

static const char decodingTab[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,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,-1,-1,-1,-1,-1,-1,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};
static unsigned char encodingTab[64]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

decodeTab 是 encondingTab 的反向映射表。所以decodeTab[i] 永远不应该是-1。事实上,预计只有 64 个值。但是decodeTab的大小是128。所以,在decodeTab中,意外的索引值被设置为-1(一个不在[0,63]中的任意数字)

char c;
unsigned char i;
...
encoding[decoding[c]]=c;
decoding[encoding[i]=i;

希望能帮助到你。

于 2019-01-11T17:38:24.397 回答