Add base64_encodev() multi-buffer Base64 encoder

Also replace base64_encode_len() inline function with macro
BASE64_ENCODED_LEN()
This commit is contained in:
Andrew Bettison 2013-11-18 11:39:23 +10:30
parent b8e0859880
commit e59a62115b
2 changed files with 40 additions and 24 deletions

50
str.c
View File

@ -24,6 +24,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <sys/uio.h>
#include <string.h> #include <string.h>
#include <ctype.h> #include <ctype.h>
#include <assert.h> #include <assert.h>
@ -86,28 +87,33 @@ const char base64_symbols[64] = {
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/' 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
}; };
size_t base64_encode(char *const dstBase64, const unsigned char *src, size_t srclen) size_t base64_encodev(char *dstBase64, const struct iovec *const iov, int const iovcnt)
{ {
char *dst = dstBase64; char *dst = dstBase64;
unsigned place = 0; unsigned place = 0;
unsigned char buf = 0; unsigned char buf = 0;
for (; srclen; --srclen, ++src) { int iovc = 0;
switch (place) { for (iovc = 0; iovc != iovcnt; ++iovc) {
case 0: unsigned char *src = iov[iovc].iov_base;
*dst++ = base64_symbols[*src >> 2]; size_t cnt = iov[iovc].iov_len;
buf = (*src << 4) & 0x3f; for (; cnt; --cnt, ++src) {
place = 1; switch (place) {
break; case 0:
case 1: *dst++ = base64_symbols[*src >> 2];
*dst++ = base64_symbols[(*src >> 4) | buf]; buf = (*src << 4) & 0x3f;
buf = (*src << 2) & 0x3f; place = 1;
place = 2; break;
break; case 1:
case 2: *dst++ = base64_symbols[(*src >> 4) | buf];
*dst++ = base64_symbols[(*src >> 6) | buf]; buf = (*src << 2) & 0x3f;
*dst++ = base64_symbols[*src & 0x3f]; place = 2;
place = 0; break;
break; case 2:
*dst++ = base64_symbols[(*src >> 6) | buf];
*dst++ = base64_symbols[*src & 0x3f];
place = 0;
break;
}
} }
} }
if (place) if (place)
@ -121,6 +127,14 @@ size_t base64_encode(char *const dstBase64, const unsigned char *src, size_t src
return dst - dstBase64; return dst - dstBase64;
} }
size_t base64_encode(char *const dstBase64, const unsigned char *src, size_t srclen)
{
struct iovec iov;
iov.iov_base = (void *) src;
iov.iov_len = srclen;
return base64_encodev(dstBase64, &iov, 1);
}
char *to_base64_str(char *const dstBase64, const unsigned char *srcBinary, size_t srcBytes) char *to_base64_str(char *const dstBase64, const unsigned char *srcBinary, size_t srcBytes)
{ {
dstBase64[base64_encode(dstBase64, srcBinary, srcBytes)] = '\0'; dstBase64[base64_encode(dstBase64, srcBinary, srcBytes)] = '\0';

14
str.h
View File

@ -124,30 +124,32 @@ size_t strn_fromhex(unsigned char *dstBinary, ssize_t dstlen, const char *src, c
* *
* @author Andrew Bettison <andrew@servalproject.com> * @author Andrew Bettison <andrew@servalproject.com>
*/ */
__SERVAL_DNA_STR_INLINE size_t base64_encode_len(size_t binaryBytes) { #define BASE64_ENCODED_LEN(binaryBytes) (((size_t)(binaryBytes) + 2) / 3 * 4)
return (binaryBytes + 2) / 3 * 4;
}
const char base64_symbols[64]; const char base64_symbols[64];
/* Encode 'srcBytes' bytes of binary data at 'srcBinary' into Base64 representation at 'dstBase64', /* Encode 'srcBytes' bytes of binary data at 'srcBinary' into Base64 representation at 'dstBase64',
* which must point to at least 'base64_encode_len(srcBytes)' bytes. The encoding is terminated * which must point to at least 'BASE64_ENCODED_LEN(srcBytes)' bytes. The encoding is terminated
* by a "=" or "==" pad to bring the total number of encoded bytes up to a multiple of 4. * by a "=" or "==" pad to bring the total number of encoded bytes up to a multiple of 4.
* *
* Returns the total number of encoded bytes writtent at 'dstBase64'. * Returns the total number of encoded bytes writtent at 'dstBase64'.
* *
* The base64_encodev() is a multi-buffer gather variant, analagous to readv(2) and writev(2).
*
* @author Andrew Bettison <andrew@servalproject.com> * @author Andrew Bettison <andrew@servalproject.com>
*/ */
size_t base64_encode(char *dstBase64, const unsigned char *srcBinary, size_t srcBytes); size_t base64_encode(char *dstBase64, const unsigned char *srcBinary, size_t srcBytes);
struct iovec;
size_t base64_encodev(char *dstBase64, const struct iovec *iov, int iovcnt);
/* The same as base64_encode() but appends a terminating NUL character to the encoded string, /* The same as base64_encode() but appends a terminating NUL character to the encoded string,
* so 'dstBase64' must point to at least 'base64_encode_len(srcBytes) + 1' bytes. * so 'dstBase64' must point to at least 'BASE64_ENCODED_LEN(srcBytes) + 1' bytes.
* *
* @author Andrew Bettison <andrew@servalproject.com> * @author Andrew Bettison <andrew@servalproject.com>
*/ */
char *to_base64_str(char *dstBase64, const unsigned char *srcBinary, size_t srcBytes); char *to_base64_str(char *dstBase64, const unsigned char *srcBinary, size_t srcBytes);
#define alloca_base64(buf,len) to_base64_str(alloca(base64_encode_len(len) + 1), (buf), (len)) #define alloca_base64(buf,len) to_base64_str(alloca(BASE64_ENCODED_LEN(len) + 1), (buf), (len))
/* Decode the string at 'srcBase64' as ASCII Base-64, writing up to 'dstsiz' decoded binary bytes at /* Decode the string at 'srcBase64' as ASCII Base-64, writing up to 'dstsiz' decoded binary bytes at
* 'dstBinary'. Returns the number of decoded binary bytes produced. If 'dstsiz' is zero or * 'dstBinary'. Returns the number of decoded binary bytes produced. If 'dstsiz' is zero or