summaryrefslogtreecommitdiffstats
path: root/decode.c
diff options
context:
space:
mode:
authorGentoo <installgentoo@endianness.com>2021-03-27 10:20:15 +1100
committerGentoo <installgentoo@endianness.com>2021-03-27 10:20:15 +1100
commitcc068dd1b885c884659e4d36e7d4aa81c52dc89c (patch)
tree73ebdfe6bade1b58fb0cec014e762d84e38b7a9a /decode.c
downloadbase64-cc068dd1b885c884659e4d36e7d4aa81c52dc89c.tar.gz
base64-cc068dd1b885c884659e4d36e7d4aa81c52dc89c.tar.bz2
base64-cc068dd1b885c884659e4d36e7d4aa81c52dc89c.zip
initial commit
Diffstat (limited to 'decode.c')
-rw-r--r--decode.c151
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;
+}