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 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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
|
/*
* 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 */
|