C - 解码base64时的位移位

时间:2014-01-22 18:05:26

标签: c base64 bit-manipulation decode

我正在尝试解码C中的base64数据。我找到了我想要使用的实现,但我不确定它是如何工作的,我希望对使用的一般语法有一些帮助/解释在这里:Base64Decode

我想要了解的代码是:

int base64decode (char *in, size_t inLen, unsigned char *out, size_t *outLen) { 
    char *end = in + inLen;
    size_t buf = 1, len = 0;

    while (in < end) {
        unsigned char c = d[*in++];

        switch (c) {
        case WHITESPACE: continue;   /* skip whitespace */
        case INVALID:    return 1;   /* invalid input, return error */
        case EQUALS:                 /* pad character, end of data */
            in = end;
            continue;
        default:
            buf = buf << 6 | c;

            /* If the buffer is full, split it into bytes */
            if (buf & 0x1000000) {
                if ((len += 3) > *outLen) return 1; /* buffer overflow */
                *out++ = buf >> 16;
                *out++ = buf >> 8;
                *out++ = buf;
                buf = 1;
            }   
        }
    }

    if (buf & 0x40000) {
        if ((len += 2) > *outLen) return 1; /* buffer overflow */
        *out++ = buf >> 10;
        *out++ = buf >> 2;
    }
    else if (buf & 0x1000) {
        if (++len > *outLen) return 1; /* buffer overflow */
        *out++ = buf >> 4;
    }

    *outLen = len; /* modify to reflect the actual output size */
    return 0;
}

我坚持* out ++ out = buf&gt;&gt; 16; ,它告诉我,out的值将等于buff,它应该是1000000向右移16位?值中甚至没有16位,所以它不会归零吗?我真的很想了解这些代码的其余部分,非常感谢任何帮助。提前谢谢!

1 个答案:

答案 0 :(得分:2)

您可以一步一步地解决这个问题。让我们跳过空格,等号和无效字符以及最后填充的代码,并关注循环和defualt子句:

size_t buf = 1;

while (in < end) {
    unsigned char c

    /* read next byte */
    c = d[*in++]; 

    /* append byte to number */
    buf = buf << 6 | c;

    /* If the buffer is full, split it into bytes */
    if (buf & 0x1000000) {
        *out++ = buf >> 16;
        *out++ = buf >> 8;
        *out++ = buf;
        buf = 1;
    }
}

代码逐字节读取,然后附加到buf。输入为6-ybit-chunks,输出应为8-bit-chunk,又称字节。 (非法输入字符是设置了前两位中的任何一个的字符。)

这个想法是使用buf作为辅助缓冲区,存储四个六位值,直到它满。然后,将该缓冲区的内容写为三个八位值。

我们从buf == 1开始:

.... .... .... .... .... .... .... ...1

空位在这里表示为点,它比零更容易阅读。 1是哨兵值。好的,读取下一个字节,用a表示。将缓冲区移动六个位置

.... .... .... .... .... .... .1.. ....    // buf = buf << 6

并做一个逻辑或数据:

.... .... .... .... .... .... .1aa aaaa    // buf = buf | 'a'

好的,下一个字节,'b':

.... .... .... .... ...1 aaaa aa.. ....    // buf = buf << 6
.... .... .... .... ...1 aaaa aabb bbbb    // buf = buf | 'b'

下一个字节'c':

.... .... .... .1aa aaaa bbbb bb.. ....    // buf = buf << 6
.... .... .... .1aa aaaa bbbb bbcc cccc    // buf = buf | 'c'

和'd':

.... ...1 aaaa aabb bbbb cccc cc.. ....    // buf = buf << 6
.... ...1 aaaa aabb bbbb cccc ccdd dddd    // buf = buf | 'd'

现在查看缓冲区是否已满。 (这是在读取每个字节后完成的,但为了清楚起见,我将其删除了。)这是通过buf0x1000000进行逐位和.... ...1 aaaa aabb bbbb cccc ccdd dddd // buf .... ...1 .... .... .... .... .... .... // 0x1000000 .... ...1 .... .... .... .... .... .... // buf & 0x1000000 完成的:

.... .... .... .... .... ...1 aaaa aabb    // buf >> 16
.... .... .... ...1 aaaa aabb bbbb cccc    // buf >> 8
.... ...1 aaaa aabb bbbb cccc ccdd dddd    // buf

这个值第一次现在是真的,这意味着我们已经读取了四个六位块,我们现在需要将数据写为三个八位块。

---- ---- ---- ---- ---- ---- aaaa aabb    // (uchar) (buf >> 16)
---- ---- ---- ---- ---- ---- bbbb cccc    // (uchar) (buf >> 8)
---- ---- ---- ---- ---- ---- ccdd dddd    // (uchar) buf

这些值写入字节,即无符号字符,将其截断为最低的8位:

buf

现在,将1重置为{{1}}并阅读下一个字节。

相关问题