summaryrefslogtreecommitdiff
path: root/spectro/base64.c
diff options
context:
space:
mode:
Diffstat (limited to 'spectro/base64.c')
-rw-r--r--spectro/base64.c215
1 files changed, 215 insertions, 0 deletions
diff --git a/spectro/base64.c b/spectro/base64.c
new file mode 100644
index 0000000..388d121
--- /dev/null
+++ b/spectro/base64.c
@@ -0,0 +1,215 @@
+
+/*
+ * Argyll Color Correction System
+ *
+ * Very simple & concise base64 encoder/decoder
+ *
+ * Author: Graeme W. Gill
+ *
+ * Copyright 2014, Graeme W. Gill
+ * All rights reserved.
+ *
+ * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
+ * see the License2.txt file for licencing details.
+ */
+
+
+#include <stdio.h>
+# define DLL_LOCAL
+#include "base64.h"
+
+static int enc(int val) {
+ val &= 0x3f;
+
+ if (val <= 25)
+ return ('A' + val);
+ if (val <= 51)
+ return ('a' + val - 26);
+ if (val <= 61)
+ return ('0' + val - 52);
+ if (val == 62)
+ return '+';
+ return '/';
+}
+
+/* Encode slen bytes into nul terminated string. */
+/* if dlen is !NULL, then set it to resulting string length excluding nul */
+/* We assume that the destination buffer is long enough at EBASE64LEN */
+void DLL_LOCAL ebase64(int *dlen, char *dst, unsigned char *src, int slen) {
+ unsigned char buf[3];
+ int i, j;
+
+ /* Do this 3 characters at a time */
+ for (j = i = 0; i < slen; i += 3) {
+ int ib;
+
+ /* Grab 3 bytes or zero pad, and count bits */
+ buf[0] = src[i]; ib = 8;
+ buf[1] = (i+1) < slen ? (ib += 8, src[i+1]) : 0;
+ buf[2] = (i+2) < slen ? (ib += 8, src[i+2]) : 0;
+
+ /* Output up to 4 encoded characters */
+ dst[j] = enc(buf[0] >> 2), j++;
+ if (ib > 6) {
+ dst[j] = enc(buf[0] << 4 | buf[1] >> 4), j++;
+ if (ib > 12) {
+ dst[j] = enc(buf[1] << 2 | buf[2] >> 6), j++;
+ if (ib > 18)
+ dst[j] = enc(buf[2]), j++;
+ }
+ }
+ }
+ if (dlen != NULL)
+ *dlen = j;
+
+ dst[j++] = '\000';
+}
+
+/* Return binary value corresponding to encoded character, */
+/* -1 for invalid character, -2 if nul terminator */
+/* (We're assuming ASCII encoding) */
+static int dec(int val) {
+ val &= 0xff;
+
+ if (val == 0)
+ return -2;
+ if (val == '+')
+ return 62;
+ if (val == '/')
+ return 63;
+ if (val < '0')
+ return -1;
+ if (val <= '9')
+ return val - '0' + 52;
+ if (val < 'A')
+ return -1;
+ if (val <= 'Z')
+ return val - 'A';
+ if (val < 'a')
+ return -1;
+ if (val <= 'z')
+ return val - 'a' + 26;
+ return -1;
+}
+
+/* Decode nul terminated string into bytes, ignoring illegal characters. */
+/* if dlen is !NULL, then set it to resulting byte length */
+/* We assume that the destination buffer is long enough at DBASE64LEN */
+void DLL_LOCAL dbase64(int *dlen, unsigned char *dst, char *src) {
+ int buf[4];
+ int j;
+
+ /* Do this 4 characters at a time */
+ for (j = 0;;) {
+ int v, ib;
+
+ /* Grab 4 characters skipping illegals, and count bits */
+ while ((buf[0] = dec(*src++)) == -1)
+ ;
+ if (buf[0] == -2)
+ break;
+ ib = 6;
+ while ((buf[1] = dec(*src++)) == -1)
+ ;
+ if (buf[1] != -2) {
+ ib += 6;
+ while ((buf[2] = dec(*src++)) == -1)
+ ;
+ if (buf[2] != -2) {
+ ib += 6;
+ while ((buf[3] = dec(*src++)) == -1)
+ ;
+ if (buf[3] != -2)
+ ib += 6;
+ else
+ buf[3] = 0;
+ } else
+ buf[2] = 0;
+ } else
+ buf[1] = 0;
+
+ /* Output up to 3 decoded bytes */
+ dst[j] = buf[0] << 2 | buf[1] >> 4, j++;
+ if (ib > 12) {
+ dst[j] = buf[1] << 4 | buf[2] >> 2, j++;
+ if (ib > 18) {
+ dst[j] = buf[2] << 6 | buf[3], j++;
+ continue; /* We didn't run out */
+ }
+ }
+ break; /* Must be done if didn't continue */
+ }
+ if (dlen != NULL)
+ *dlen = j;
+}
+
+
+#ifdef STANDALONE_TEST
+/* test base64 code */
+
+#include <numlib.h>
+
+#define MAXLEN 30
+
+int main() {
+ unsigned char src[MAXLEN], check[MAXLEN];
+ char dst[EBASE64LEN(MAXLEN) + 1];
+ int n, slen, dlen, chlen, i, j;
+
+ printf("Testing base64 encode/decode:\n");
+
+ for (n = 0; n < 10000000; n++) {
+
+ /* Create a random binary */
+ slen = i_rand(0, MAXLEN);
+ for (i = 0; i < slen; i++)
+ src[i] = i_rand(0, 255);
+
+ /* Encode it */
+ ebase64(&dlen, dst, src, slen);
+
+ if (dlen != EBASE64LEN(slen)) {
+ error("%d: Wrong encoded length, src %d, is %d should be %d\n",n,slen,dlen,EBASE64LEN(slen));
+ }
+
+ /* Decode it */
+ dbase64(&chlen, check, dst);
+
+ if (chlen != DBASE64LEN(dlen)) {
+ error("%d: Wrong decoded length, enc %d, is %d should be %d\n",n,dlen,chlen,DBASE64LEN(dlen));
+ }
+
+ /* Check characters match */
+ for (i = 0; i < slen; i++) {
+ if (src[i] != check[i]) {
+ for (j = 0; j < slen; j++) {
+ printf("%02X ",src[j]);
+ if ((j % 3) == 2)
+ printf(" ");
+ }
+ printf("\n");
+
+ for (j = 0; j < dlen; j++) {
+ printf("%c ",dst[j]);
+ if ((j % 4) == 3)
+ printf(" ");
+ }
+ printf("\n");
+ for (j = 0; j < slen; j++) {
+ printf("%02X ",check[j]);
+ if ((j % 3) == 2)
+ printf(" ");
+ }
+ printf("\n\n");
+ printf("src len %d, dst len %d\n",slen, dlen);
+ error("%d: Verify error at byte %d, is 0x%x should be 0x%x\n",n,i,check[i],src[i]);
+ }
+ }
+
+ if ((n % 10000) == 0)
+ printf("done %d tests\n",n);
+ }
+ printf("Testing %d conversions base64 complete\n",n);
+}
+
+#endif /* STANDALONE_TEST */