2017年9月9日土曜日

Encode/Decode Base64

はじめに

独自実装した理由はとくにないです.
以下のような変種が自由に作れるから?
s32 encodeBase64(FILE* file, s32 length, const u8* src);
s32 decodeBase64(u8* dst, FILE* file);

共通処理

Base64の文字テーブルと, インデックス検索関数.
/*
This is free and unencumbered software released into the public domain.
*/
static const s8 Base64Chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const s8 Base64PadChar = '=';
s32 getIndexBase64Chars(s8 c)
{
    if('A'<=c && c<='Z'){
        return c-'A';

    }else if('a'<=c && c<='z'){
        return c-'a' + 26;

    }else if('0'<=c && c<='9'){
        return c-'0' + 52;
    }
    for(s32 i=62; i<64; ++i){
        if(Base64Chars[i]==c){
            return i;
        }
    }
    return 0;
}

bool isBase64(s32 c)
{
    return std::isalnum(c) || '+'==c || '/'==c;
}

s32 getLengthEncodedBase64(s32 l)
{
    l = l<<3;
    s32 n0 = l/6;
    if(0<(l-n0*6)){
        ++n0;
    }
    s32 n1 = ((n0 + 3)>>2)<<2;
    return n1;
}

s32 getLengthDecodedBase64(s32 l)
{
    return (l*6 + 7)>>3;
}

Encode

s32 encodeBase64(s8* dst, s32 length, const u8* src)
{
    ASSERT(NULL != dst);
    ASSERT(0<=length);
    ASSERT(NULL != src);

    u8 tmp[3];
    s32 d=0;
    s32 l=0;
    for(s32 i=0; i<length; ++i){
        tmp[l] = src[i];
        ++l;
        if(3<=l){
            dst[d+0] = Base64Chars[tmp[0]>>2];
            dst[d+1] = Base64Chars[((tmp[0]&0x03U)<<4) | (tmp[1]>>4)];
            dst[d+2] = Base64Chars[((tmp[1]&0x0FU)<<2) | (tmp[2]>>6)];
            dst[d+3] = Base64Chars[(tmp[2]&0x3FU)];
            d += 4;
            l = 0;
        }
    }
    if(0<l){
        for(s32 j=l; j<3; ++j){
            tmp[j] = 0;
        }
        dst[d+0] = Base64Chars[tmp[0]>>2];
        dst[d+1] = Base64Chars[((tmp[0]&0x03U)<<4) | (tmp[1]>>4)];
        dst[d+2] = Base64Chars[((tmp[1]&0x0FU)<<2) | (tmp[2]>>6)];
        dst[d+3] = Base64Chars[(tmp[2]&0x3FU)];
        s32 n = l<<3;
        s32 r = (l<<3)/6;
        if(0<(n-r*6)){
            ++l;
        }
        for(s32 j=l; j<4; ++j){
            dst[d+j] = Base64PadChar;
        }
        d+=4;
    }
    return d;
}

Decode

s32 decodeBase64(u8* dst, s32 length, const s8* src)
{
    ASSERT(NULL != dst);
    ASSERT(0<=length);
    ASSERT(NULL != src);

    s32 l=0;
    s32 d=0;
    u8 tmp[4];
    for(s32 i=0;
        i<length && isBase64(src[i]) && Base64PadChar != src[i];
        ++i)
    {
        tmp[l] = static_cast<u8>(getIndexBase64Chars(src[i]));
        ++l;
        if(4<=l){
            dst[d+0] = (tmp[0]<<2) | ((tmp[1]&0x30U)>>4);
            dst[d+1] = (tmp[1]<<4) | ((tmp[2]&0x3CU)>>2);
            dst[d+2] = (tmp[2]<<6) | tmp[3];
            d += 3;
            l=0;
        }
    }
    if(0<l){
        for(s32 i=l; i<4; ++i){
            tmp[i] = 0;
        }
        dst[d+0] = (tmp[0]<<2) | ((tmp[1]&0x30U)>>4);
        dst[d+1] = (tmp[1]<<4) | ((tmp[2]&0x3CU)>>2);
        dst[d+2] = (tmp[2]<<6) | tmp[3];
        d += (l*6)>>3;
    }
    return d;
}

0 件のコメント:

コメントを投稿