aboutsummaryrefslogblamecommitdiff
path: root/xsig/src/base64.cpp
blob: c5f6b321977c94ddbcf1993f082760d70c5dc3d2 (plain) (tree)
1
2
3
4
5
6
7
8
9

                  





                     
                                                                                                      
 
                                                                            
 
                                                              

























                                                       
                                      









                                             
                                        









                                                    
                                                 






















                                                    
                                       



                
                                                                







































                                                  
//Chris Xiong 2022
//License: MPL-2.0
#include <string>
#include <cstdint>
#include <cstdlib>

#include "base64.hpp"

const char *base64_encoder::b64c = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

base64_encoder::base64_encoder() : counter(0), rem(0), ret(std::string()) {}

void base64_encoder::encode_data(const void *data, size_t len)
{
    const uint8_t *u8d = (uint8_t*) data;
    for (size_t i = 0; i < len; ++i)
    {
        ++counter;
        if (counter == 3) counter = 0;
        switch (counter)
        {
            case 0:
                rem |= (u8d[i] >> 6);
                ret.push_back(b64c[rem]);
                ret.push_back(b64c[u8d[i] & 0b111111]);
            break;
            case 1:
                ret.push_back(b64c[u8d[i] >> 2]);
                rem = (u8d[i] & 0b11) << 4;
            break;
            case 2:
                rem |= (u8d[i] >> 4);
                ret.push_back(b64c[rem]);
                rem = (u8d[i] & 0b1111) << 2;
            break;
        }
    }
}

std::string base64_encoder::finalize()
{
    if (counter)
    {
        ret.push_back(b64c[rem]);
        for (int i = 0; i < 3 - counter; ++i)
            ret.push_back('=');
    }
    return ret;
}

const uint8_t base64_decoder::b64v[] = {
    65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
    65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,
    65,65,65,65,65,65,65,65,65,65,65,62,65,65,65,63,
    52,53,54,55,56,57,58,59,60,61,65,65,65,64,65,65,
    65, 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,65,65,65,65,65,
    65,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,65,65,65,65,65
};

base64_decoder::base64_decoder(std::string &&b) :
    s(b),
    invalid(false),
    rem(0),
    counter(0),
    bp(0)
{
    size_t npadd = 0;
    for (auto ri = s.rbegin(); ri != s.rend(); ++ri)
        if (*ri == '=')
            ++npadd;
        else break;
    dlen = (s.length() - npadd) / 4 * 3;
    switch (npadd)
    {
        case 0: break;
        case 1: dlen += 2; break;
        case 2: dlen += 1; break;
        default:
            dlen = 0;
            invalid = true;
    }
}

size_t base64_decoder::decoded_length()
{
    return dlen;
}

size_t base64_decoder::decode_data(const void *data, size_t len)
{
    uint8_t *rp = (uint8_t*)data;
    for (; bp < s.size(); ++bp)
    {
        ++counter;
        if (counter == 4) counter = 0;
        if (s[bp] == '=') break;
        if (s[bp] < 0 || b64v[s[bp]] > 64)
        {
            invalid = true;
            return 0;
        }
        switch (counter)
        {
            case 0:
                rem |= b64v[s[bp]];
                *(rp++) = rem;
            break;
            case 1:
                rem = b64v[s[bp]] << 2;
            break;
            case 2:
                rem |= b64v[s[bp]] >> 4;
                *(rp++) = rem;
                rem = (b64v[s[bp]] & 0b1111) << 4;
            break;
            case 3:
                rem |= b64v[s[bp]] >> 2;
                *(rp++) = rem;
                rem = (b64v[s[bp]] & 0b11) << 6;
            break;
        }
        if (rp - (uint8_t*)data == len)
        {
            ++bp;
            break;
        }
    }
    return rp - (uint8_t*)data;
}