diff options
Diffstat (limited to 'decode.c')
-rw-r--r-- | decode.c | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/decode.c b/decode.c new file mode 100644 index 0000000..3368e3c --- /dev/null +++ b/decode.c @@ -0,0 +1,151 @@ +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> //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<size;++i) + { + //check that string[i] is a valid base64 char, then convert it to the integer value. + if ((string[i] <= 'z')&&(string[i] >= '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; +} |