/* Copyright (C) 2021 Gentoo-libre Install
This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program. If not, see .
*/
#include
#include
#include //for CHAR_BIT
#include "decode.h"//for stripNewlines()
//macros for writing bits
#define BITMASK(b) (1 << ((b) % CHAR_BIT))
#define BITSLOT(b) ((b) / CHAR_BIT)
#define BITSET(a, b) ((a)[BITSLOT(b)] |= BITMASK(b))
#define BITCLEAR(a, b) ((a)[BITSLOT(b)] &= ~BITMASK(b))
//#define BITTEST(a, b) ((a)[BITSLOT(b)] & BITMASK(b))
//#define BITNSLOTS(nb) ((nb + CHAR_BIT - 1) / CHAR_BIT)
//base64Decode: Decodes base64 into binary output data. Takes a pointer to a '\0' terminated input string and the size of the string, not including '\0' (e.g. strlen(string))
int base64Decode(unsigned char *string, int size)
{
if (!size){return -1;}//Catches the case of feeding the function a negative or 0 length.
//strip newlines from input string, since handling them in body is too painful/slow
size = stripNewlines(string, size);
//printf("%d\n", size);
//printf("%s\n", string);
//printf("%d\n", size%4);
if (size % 4 != 0){return -1;}//if the number of base64 characters sent can't be perfectly divided by 4, the base64 string is invalid.
int base64value;//input char converted to it's matching base64 value
int i;//i is located at the position of the char currently being processed
int outputPos = 0;//i and the output string doesn't match up
//needs +1 to work "correctly" (for 4 chars anyway)
for (i=0; i+1= 'a')){base64value = string[i] - 71; goto firstChar;}
if ((string[i] <= 'Z')&&(string[i] >= 'A')){base64value = string[i] - 65; goto firstChar;}
if ((string[i] <= '9')&&(string[i] >= '0')){base64value = string[i] + 4; goto firstChar;}
if (string[i] == '+'){base64value = 62; goto firstChar;}
if (string[i] == '/'){base64value = 63; goto firstChar;}
else{return -1;}//not a base64 character
firstChar:; //printf("%d\n", base64value);
//clear the output byte ready for bitset
string[outputPos] = '\0';
/*
| string[0] |
|X|X|X|X|X|X|X|X|
|7|6|5|4|3|2|1|0|
|-|-|-|-|-|-|
*/
//bitset the output char to the correct value
if (base64value >= 32){BITSET(string+outputPos,7); base64value -= 32;}//if base64value >= 32, the h
if (base64value >= 16){BITSET(string+outputPos,6); base64value -= 16;}
if (base64value >= 8){BITSET(string+outputPos,5); base64value -= 8;}
if (base64value >= 4){BITSET(string+outputPos,4); base64value -= 4;}
if (base64value >= 2){BITSET(string+outputPos,3); base64value -= 2;}
if (base64value >= 1){BITSET(string+outputPos,2);}
++i;
if ((string[i] <= 'z')&&(string[i] >= 'a')){base64value = string[i] - 71; goto secondChar;}
if ((string[i] <= 'Z')&&(string[i] >= 'A')){base64value = string[i] - 65; goto secondChar;}
if ((string[i] <= '9')&&(string[i] >= '0')){base64value = string[i] + 4; goto secondChar;}
if (string[i] == '+'){base64value = 62; goto secondChar;}
if (string[i] == '/'){base64value = 63; goto secondChar;}
else{return -1;}//not a base64 character
secondChar:; //printf("%d\n", base64value);
/* | string0] |
|7|6|5|4|3|2|1|0|
|-|-|
*/
if (base64value >= 32){BITSET(string+outputPos,1); base64value -= 32;}
if (base64value >= 16){BITSET(string+outputPos,0); base64value -= 16;}
++outputPos;
//clear the output byte ready for bitset
string[outputPos] = '\0';
/* | string[0] | string[1] |
|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
|-|-|-|-|
*/
//bits 4-7 of second char
if (base64value >= 8){BITSET(string+outputPos,7); base64value -= 8;}
if (base64value >= 4){BITSET(string+outputPos,6); base64value -= 4;}
if (base64value >= 2){BITSET(string+outputPos,5); base64value -= 2;}
if (base64value >= 1){BITSET(string+outputPos,4);}
++i;
if ((string[i] <= 'z')&&(string[i] >= 'a')){base64value = string[i] - 71; goto thirdChar;}
if ((string[i] <= 'Z')&&(string[i] >= 'A')){base64value = string[i] - 65; goto thirdChar;}
if ((string[i] <= '9')&&(string[i] >= '0')){base64value = string[i] + 4; goto thirdChar;}
if (string[i] == '+'){base64value = 62; goto thirdChar;}
if (string[i] == '/'){base64value = 63; goto thirdChar;}
if (string[i] == '='){return outputPos;}//if padding character detected, just return
else{return -1;}//not a base64 character
thirdChar:; //printf("%d\n", base64value);
/* | string[0] | string[1] |
|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
|-|-|-|-|
*/
if (base64value >= 32){BITSET(string+outputPos,3); base64value -= 32;}
if (base64value >= 16){BITSET(string+outputPos,2); base64value -= 16;}
if (base64value >= 8){BITSET(string+outputPos,1); base64value -= 8;}
if (base64value >= 4){BITSET(string+outputPos,0); base64value -= 4;}
++outputPos;
//clear the output byte ready for bitset
string[outputPos] = '\0';
/* | string[0] | string[1] | string[2] |
|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
|-|-|
*/
if (base64value >= 2){BITSET(string+outputPos,7); base64value -= 2;}
if (base64value >= 1){BITSET(string+outputPos,6); --base64value;}
++i;
if ((string[i] <= 'z')&&(string[i] >= 'a')){base64value = string[i] - 71; goto forthChar;}
if ((string[i] <= 'Z')&&(string[i] >= 'A')){base64value = string[i] - 65; goto forthChar;}
if ((string[i] <= '9')&&(string[i] >= '0')){base64value = string[i] + 4; goto forthChar;}
if (string[i] == '+'){base64value = 62; goto forthChar;}
if (string[i] == '/'){base64value = 63; goto forthChar;}
if (string[i] == '='){return outputPos;}//if padding character detected, just return
else{return -1;}//not a base64 character
forthChar:; //printf("%d\n", base64value);
/* | string[0] | string[1] | string[2] |
|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|7|6|5|4|3|2|1|0|
|-|-|-|-|-|-|
*/
if (base64value >= 32){BITSET(string+outputPos,5); base64value -= 32;}
if (base64value >= 16){BITSET(string+outputPos,4); base64value -= 16;}
if (base64value >= 8){BITSET(string+outputPos,3); base64value -= 8;}
if (base64value >= 4){BITSET(string+outputPos,2); base64value -= 4;}
if (base64value >= 2){BITSET(string+outputPos,1); base64value -= 2;}
if (base64value >= 1){BITSET(string+outputPos,0);}
++outputPos;
}
return outputPos;
}