美文网首页
对于C/C++实现Base64的Encode代码的阅读日记

对于C/C++实现Base64的Encode代码的阅读日记

作者: anliner | 来源:发表于2020-03-16 18:22 被阅读0次

    首先了解了下Base64的实现原理:https://baijiahao.baidu.com/s?id=1644892102150918183&wfr=spider&for=pc
    大概内容就是,base64基于一个含有64个字符的编码表(A-Z,a-z,0-9,+,/),将原文进行转码,其步骤就是将原文按每三个字节一组分割,每三个字节又按六位一组分为四组,然后高位补零,所以输出结果里每个字节最大值也就63,也就是对应了base64的编码表。
    接下来直接看base64.c文件的代码

    int base64_encode(unsigned char *dst, int *dlen, const unsigned char *src, int slen) {
        int i, n;
        int C1, C2, C3;
        unsigned char *p;
    
        if (slen == 0)
            return (0);
    
        /**
         * 首先计算传入进来的原文按六位一组,可以分成多少组
         * 所以将slen * 8,然后再除6 (由于8是2的3次方,用乘法算太耗时,所以直接左移3位)
         */
        n = (slen << 3) / 6;
    
        /**
         * 由于原文长度并不一定是3的倍数,可能多1或2个字节,所以还需要计算是否多出字节
         * 由于是将3字节按4个6位分割,需要以24位一组的规则计算新数组空间
         * 按照8:6 和 16:12的比例,那么多出1个字节,原文总位数除以6,余2;多出2个字节,余4
         * 再结合每组24位的原则,原文多1个字节,在n的基础上,新数组还差18位即3字节空间,原文多2字节,新数组还差12位即2字节空间
         * 所以当余2,n需要自加3,当余4,n需要自加2
         */
        switch ((slen << 3) - (n * 6)) {
            case 2:
                n += 3;
                break;
            case 4:
                n += 2;
                break;
            default:
                break;
        }
    
        /**
         * 按理说按照以上计算,最终n的值就是新数组的长度,所以dlen只要不小于n即可
         * 但我不明白为什么这里的判断是dlen要大于n,不知道是不是为了字符串结尾\0留位置,但也没看代码里结尾添加字符串的结尾标识啊,啊,不懂c啊
         */
        if (*dlen < n + 1) {
            *dlen = n + 1;
            return (POLARSSL_ERR_BASE64_BUFFER_TOO_SMALL);
        }
    
        /**
         * 这里是将原文按3字节分组,得到组数,多余的1、2字节后面单独计算
         */
        n = (slen / 3) * 3;
    
        /**
         * 按组数循环取原文里的字节,每次取3个,这里用了新指针p,指向地址与传参的dst一样,联系上下文,我个人理解是为了计算新数组实际长度
         * 但是用strlen不也可以计算dst的长度么,不明白为什么这样做
         * em....好像直接用dst运算,最后指针已经指向字符串末尾了,不过也不是没有办法回到开头,这个p还是让我很纠结
         */
        for (i = 0, p = dst; i < n; i += 3) {
            C1 = *src++;
            C2 = *src++;
            C3 = *src++;
    
            /**
             * 首先将第一字节右移2位,得到左6位,与上0x3F,高2位置0,得到第一个6位
             * 然后在编码表里进行转码,得到新组的第一字节
             */
            *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
            /**
             * 接着将第一字节与3,即00000011,得到低2位,然后左移4位,
             * 然后将第二字节右移4位,做加法运算,得到第二个6位,转码得到新组的第二字节
             */
            *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
            /**
             * 将第二字节与15,即00001111,得到低4位,然后左移2位,
             * 然后将第三字节右移6位,得到高2位,做加法运算,得到第三个6位,转码得到新组的第三字节
             */
            *p++ = base64_enc_map[(((C2 & 15) << 2) + (C3 >> 6)) & 0x3F];
            /**
             * 最后将第三字节与上0x3F,清除高2位,得到低6位,即第四个6位,转码得到新组的第四字节
             */
            *p++ = base64_enc_map[C3 & 0x3F];
        }
        //以上将正好可以按3字节一组分割的内容全部转码完毕
    
        /**
         * 接下来判断原文按3字节分组后,是否还多出不够一组的内容
         */
        if (i < slen) {
            /**
             * 既然多出内容,那么至少多一个,所以第一字节直接取
             * 对第二字节需要判断
             */
            C1 = *src++;
            C2 = ((i + 1) < slen) ? *src++ : 0;
    
            /**
             * 新组第一二字节可直接取6位然后转码
             */
            *p++ = base64_enc_map[(C1 >> 2) & 0x3F];
            *p++ = base64_enc_map[(((C1 & 3) << 4) + (C2 >> 4)) & 0x3F];
    
            /**
             * 如果原文只多出1字节,那么新组第三字节肯定为0,那么按照规则,空字符用 '=' 代替
             * 如果多出2字节,则还继续进行取6位,转码的运算
             */
            if ((i + 1) < slen)
                *p++ = base64_enc_map[((C2 & 15) << 2) & 0x3F];
            else *p++ = '=';
            /**
             * 由于最多多出2字节,所以新组第四字节肯定没有值可以取,也就是空字符,所以直接转换为 '='
             */
            *p++ = '=';
        }
    
        /**
         * 这里我的理解是计算字符数组dst(p)的长度,但还是那句话,为啥不用strlen(dst)计算
         */
        *dlen = p - dst;
        *p = 0;
    
        return (0);
    }
    

    相关文章

      网友评论

          本文标题:对于C/C++实现Base64的Encode代码的阅读日记

          本文链接:https://www.haomeiwen.com/subject/kpgtyhtx.html