mirror of
https://github.com/servalproject/serval-dna.git
synced 2025-04-15 06:36:46 +00:00
Move Base64 conversions from "str.h" to "base64.h"
This commit is contained in:
parent
cd766cd480
commit
5b3d997896
208
base64.c
Normal file
208
base64.c
Normal file
@ -0,0 +1,208 @@
|
||||
/*
|
||||
Serval Base64 primitives
|
||||
Copyright (C) 2012-2016 Serval Project Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include "base64.h"
|
||||
#include "str.h" // for Serval ctype
|
||||
#include <stdint.h> // for uint8_t
|
||||
#include <stdio.h> // for NULL
|
||||
#include <sys/uio.h> // for iovec
|
||||
#include <assert.h>
|
||||
|
||||
const char base64_symbols[65] = {
|
||||
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
|
||||
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
|
||||
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
|
||||
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/',
|
||||
'='
|
||||
};
|
||||
|
||||
const char base64url_symbols[65] = {
|
||||
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
|
||||
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
|
||||
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
|
||||
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','-','_',
|
||||
'='
|
||||
};
|
||||
|
||||
static size_t _base64_encodev(const char symbols[], char *dstBase64, const struct iovec *const iov, int const iovcnt)
|
||||
{
|
||||
char *dst = dstBase64;
|
||||
unsigned place = 0;
|
||||
unsigned char buf = 0;
|
||||
int iovc = 0;
|
||||
for (iovc = 0; iovc != iovcnt; ++iovc) {
|
||||
unsigned char *src = iov[iovc].iov_base;
|
||||
size_t cnt = iov[iovc].iov_len;
|
||||
for (; cnt; --cnt, ++src) {
|
||||
switch (place) {
|
||||
case 0:
|
||||
*dst++ = symbols[*src >> 2];
|
||||
buf = (*src << 4) & 0x3f;
|
||||
place = 1;
|
||||
break;
|
||||
case 1:
|
||||
*dst++ = symbols[(*src >> 4) | buf];
|
||||
buf = (*src << 2) & 0x3f;
|
||||
place = 2;
|
||||
break;
|
||||
case 2:
|
||||
*dst++ = symbols[(*src >> 6) | buf];
|
||||
*dst++ = symbols[*src & 0x3f];
|
||||
place = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (place)
|
||||
*dst++ = symbols[buf];
|
||||
switch (place) {
|
||||
case 1:
|
||||
*dst++ = symbols[64];
|
||||
case 2:
|
||||
*dst++ = symbols[64];
|
||||
}
|
||||
return dst - dstBase64;
|
||||
}
|
||||
|
||||
size_t base64_encodev(char *dstBase64, const struct iovec *const iov, int const iovcnt)
|
||||
{
|
||||
return _base64_encodev(base64_symbols, dstBase64, iov, iovcnt);
|
||||
}
|
||||
|
||||
size_t base64url_encodev(char *dstBase64, const struct iovec *const iov, int const iovcnt)
|
||||
{
|
||||
return _base64_encodev(base64url_symbols, dstBase64, iov, iovcnt);
|
||||
}
|
||||
|
||||
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(base64_symbols, dstBase64, &iov, 1);
|
||||
}
|
||||
|
||||
size_t base64url_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(base64url_symbols, dstBase64, &iov, 1);
|
||||
}
|
||||
|
||||
char *to_base64_str(char *const dstBase64, const unsigned char *srcBinary, size_t srcBytes)
|
||||
{
|
||||
dstBase64[base64_encode(dstBase64, srcBinary, srcBytes)] = '\0';
|
||||
return dstBase64;
|
||||
}
|
||||
|
||||
char *to_base64url_str(char *const dstBase64, const unsigned char *srcBinary, size_t srcBytes)
|
||||
{
|
||||
dstBase64[base64url_encode(dstBase64, srcBinary, srcBytes)] = '\0';
|
||||
return dstBase64;
|
||||
}
|
||||
|
||||
static size_t _base64_decode(unsigned char *dstBinary, size_t dstsiz, const char *const srcBase64, size_t srclen,
|
||||
const char **afterp, int flags, int (*skip_pred)(int),
|
||||
int (*isdigit_pred)(int), int (*ispad_pred)(int), uint8_t (*todigit)(char)
|
||||
)
|
||||
{
|
||||
uint8_t buf = 0;
|
||||
size_t digits = 0;
|
||||
unsigned pads = 0;
|
||||
size_t bytes = 0;
|
||||
const char *const srcend = srcBase64 + srclen;
|
||||
const char *src = srcBase64;
|
||||
const char *first_pad = NULL;
|
||||
for (; srclen == 0 || (src < srcend); ++src) {
|
||||
int isdigit = isdigit_pred(*src);
|
||||
int ispad = ispad_pred(*src);
|
||||
if (!isdigit && !ispad && skip_pred && skip_pred(*src))
|
||||
continue;
|
||||
assert(pads <= 2);
|
||||
if (pads == 2)
|
||||
break;
|
||||
int place = digits & 3;
|
||||
if (pads == 1) {
|
||||
if (place == 3)
|
||||
break;
|
||||
assert(place == 2);
|
||||
if (ispad) {
|
||||
++pads;
|
||||
continue; // consume trailing space before ending
|
||||
}
|
||||
// If only one pad character was present but there should be two, then don't consume the first
|
||||
// one.
|
||||
assert(first_pad != NULL);
|
||||
src = first_pad;
|
||||
break;
|
||||
}
|
||||
assert(pads == 0);
|
||||
if (ispad && place >= 2) {
|
||||
first_pad = src;
|
||||
++pads;
|
||||
continue;
|
||||
}
|
||||
if (!isdigit)
|
||||
break;
|
||||
++digits;
|
||||
if (dstBinary && bytes < dstsiz) {
|
||||
uint8_t d = todigit(*src);
|
||||
switch (place) {
|
||||
case 0:
|
||||
buf = d << 2;
|
||||
break;
|
||||
case 1:
|
||||
dstBinary[bytes++] = buf | (d >> 4);
|
||||
buf = d << 4;
|
||||
break;
|
||||
case 2:
|
||||
dstBinary[bytes++] = buf | (d >> 2);
|
||||
buf = d << 6;
|
||||
break;
|
||||
case 3:
|
||||
dstBinary[bytes++] = buf | d;
|
||||
break;
|
||||
}
|
||||
} else if (flags & B64_CONSUME_ALL) {
|
||||
switch (place) {
|
||||
case 1: case 2: case 3: ++bytes;
|
||||
}
|
||||
} else
|
||||
break;
|
||||
}
|
||||
if (afterp)
|
||||
*afterp = src;
|
||||
else if (*src)
|
||||
return 0;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
size_t base64_decode(unsigned char *dstBinary, size_t dstsiz, const char *const srcBase64, size_t srclen,
|
||||
const char **afterp, int flags, int (*skip_pred)(int))
|
||||
{
|
||||
return _base64_decode(dstBinary, dstsiz, srcBase64, srclen, afterp, flags, skip_pred, is_base64_digit, is_base64_pad, base64_digit);
|
||||
}
|
||||
|
||||
|
||||
size_t base64url_decode(unsigned char *dstBinary, size_t dstsiz, const char *const srcBase64, size_t srclen,
|
||||
const char **afterp, int flags, int (*skip_pred)(int))
|
||||
{
|
||||
return _base64_decode(dstBinary, dstsiz, srcBase64, srclen, afterp, flags, skip_pred, is_base64url_digit, is_base64url_pad, base64url_digit);
|
||||
}
|
98
base64.h
Normal file
98
base64.h
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
Serval Base64 primitives
|
||||
Copyright (C) 2012-2016 Serval Project Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef __SERVAL_DNA__BASE64_H__
|
||||
#define __SERVAL_DNA__BASE64_H__
|
||||
|
||||
#include <sys/types.h> // for size_t
|
||||
#include <alloca.h>
|
||||
|
||||
/* Return the number of bytes required to represent 'binaryBytes' bytes of binary data encoded
|
||||
* into Base64 form.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
#define BASE64_ENCODED_LEN(binaryBytes) (((size_t)(binaryBytes) + 2) / 3 * 4)
|
||||
|
||||
/* Array of encoding symbols. Entry [64] is the pad character (usually '=').
|
||||
*/
|
||||
extern const char base64_symbols[65];
|
||||
extern const char base64url_symbols[65];
|
||||
|
||||
/* Encode 'srcBytes' bytes of binary data at 'srcBinary' into Base64 representation at 'dstBase64'
|
||||
* (or Base64-URL representation at 'dstBase64url'), 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.
|
||||
*
|
||||
* 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>
|
||||
*/
|
||||
size_t base64_encode(char *dstBase64, const unsigned char *srcBinary, size_t srcBytes);
|
||||
size_t base64url_encode(char *dstBase64url, const unsigned char *srcBinary, size_t srcBytes);
|
||||
struct iovec;
|
||||
size_t base64_encode(char *dstBase64, const unsigned char *srcBinary, size_t srcBytes);
|
||||
size_t base64url_encodev(char *dstBase64url, const struct iovec *iov, int iovcnt);
|
||||
|
||||
/* The same as base64_encode() but appends a terminating NUL character to the encoded string,
|
||||
* so 'dstBase64' must point to at least 'BASE64_ENCODED_LEN(srcBytes) + 1' bytes.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
char *to_base64_str(char *dstBase64, const unsigned char *srcBinary, size_t srcBytes);
|
||||
char *to_base64url_str(char *dstBase64url, const unsigned char *srcBinary, size_t srcBytes);
|
||||
|
||||
#define alloca_base64(buf,len) to_base64_str(alloca(BASE64_ENCODED_LEN(len) + 1), (buf), (len))
|
||||
#define alloca_base64url(buf,len) to_base64url_str(alloca(BASE64_ENCODED_LEN(len) + 1), (buf), (len))
|
||||
|
||||
/* Decode the string at 'srcBase64' as ASCII Base64 or Base64-URL (as per RFC-4648), writing up to
|
||||
* 'dstsiz' decoded binary bytes at 'dstBinary'. Returns the number of decoded binary bytes
|
||||
* produced. If 'dstsiz' is zero or 'dstBinary' is NULL, no binary bytes are produced and returns
|
||||
* zero.
|
||||
*
|
||||
* If the 'afterp' pointer is not NULL, then sets *afterp to point to the first character in
|
||||
* 'srcBase64' where decoding stopped for whatever reason.
|
||||
*
|
||||
* If 'srclen' is 0, then the string at 'stcBase64' is assumed to be NUL-terminated, and decoding
|
||||
* runs until the first non-Base64-digit is encountered. If 'srclen' is nonzero, then decoding will
|
||||
* cease at the first non-Base64-digit or when 'srclen' bytes at 'srcBase64' have been decoded,
|
||||
* whichever comes first.
|
||||
*
|
||||
* If 'skip_pred' is not NULL, then all leading, internal and trailing characters C which are not a
|
||||
* valid Base64 digit or pad '=' will be skipped if skip_pred(C) returns true. Otherwise, decoding
|
||||
* ends at C.
|
||||
*
|
||||
* If the B64_CONSUME_ALL flag is set, then once the 'dstsiz' limit is reached (or if 'dstBinary' is
|
||||
* NULL), the Base64 decoding process continues without actually writing decoded bytes, but instead
|
||||
* counts them and advances through the 'srcBase64' buffer as usual. The return value is then the
|
||||
* number of binary bytes that would be decoded were all available Base64 decoded from 'srcBase64',
|
||||
* and *afterp points to the first character beyond the end of the decoded source characters.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
size_t base64_decode(unsigned char *dstBinary, size_t dstsiz, const char *const srcBase64, size_t srclen,
|
||||
const char **afterp, int flags, int (*skip_pred)(int));
|
||||
size_t base64url_decode(unsigned char *dstBinary, size_t dstsiz, const char *const srcBase64url, size_t srclen,
|
||||
const char **afterp, int flags, int (*skip_pred)(int));
|
||||
|
||||
#define B64_CONSUME_ALL (1 << 0)
|
||||
|
||||
#endif // __SERVAL_DNA__BASE64_H__
|
@ -24,6 +24,7 @@ HDRS= fifo.h \
|
||||
cli.h \
|
||||
str.h \
|
||||
numeric_str.h \
|
||||
base64.h \
|
||||
rotbuf.h \
|
||||
mem.h \
|
||||
os.h \
|
||||
|
@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "log.h"
|
||||
#include "debug.h"
|
||||
#include "numeric_str.h"
|
||||
#include "base64.h"
|
||||
#include "strbuf.h"
|
||||
#include "strbuf_helpers.h"
|
||||
#include "net.h"
|
||||
|
@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "conf.h"
|
||||
#include "httpd.h"
|
||||
#include "numeric_str.h"
|
||||
#include "base64.h"
|
||||
#include "strbuf_helpers.h"
|
||||
|
||||
DECLARE_HANDLER("/restful/meshms/", restful_meshms_);
|
||||
|
@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#include "serval.h"
|
||||
#include "conf.h"
|
||||
#include "httpd.h"
|
||||
#include "base64.h"
|
||||
#include "strbuf_helpers.h"
|
||||
|
||||
DECLARE_HANDLER("/restful/rhizome/bundlelist.json", restful_rhizome_bundlelist_json);
|
||||
|
@ -24,6 +24,7 @@ SERVAL_CLIENT_SOURCES = \
|
||||
strbuf_helpers.c \
|
||||
str.c \
|
||||
numeric_str.c \
|
||||
base64.c \
|
||||
strlcpy.c \
|
||||
uuid.c \
|
||||
whence.c \
|
||||
|
193
str.c
193
str.c
@ -20,17 +20,14 @@
|
||||
#define __SERVAL_DNA__STR_INLINE
|
||||
#include "str.h"
|
||||
#include "strbuf_helpers.h"
|
||||
#include "constants.h"
|
||||
#include <sodium.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/uio.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h> // for NULL
|
||||
#include <sys/uio.h> // for iovec
|
||||
#include <string.h> // for strlen(), strncmp() etc.
|
||||
#include <ctype.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <errno.h>
|
||||
|
||||
const char hexdigit_upper[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
|
||||
const char hexdigit_lower[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
|
||||
@ -194,190 +191,6 @@ size_t www_form_uri_decode(char *const dst, ssize_t dstsiz, const char *srcUrien
|
||||
return _uri_decode(1, dst, dstsiz, srcUrienc, srclen, afterp);
|
||||
}
|
||||
|
||||
const char base64_symbols[65] = {
|
||||
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
|
||||
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
|
||||
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
|
||||
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/',
|
||||
'='
|
||||
};
|
||||
|
||||
const char base64url_symbols[65] = {
|
||||
'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
|
||||
'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
|
||||
'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
|
||||
'w','x','y','z','0','1','2','3','4','5','6','7','8','9','-','_',
|
||||
'='
|
||||
};
|
||||
|
||||
static size_t _base64_encodev(const char symbols[], char *dstBase64, const struct iovec *const iov, int const iovcnt)
|
||||
{
|
||||
char *dst = dstBase64;
|
||||
unsigned place = 0;
|
||||
unsigned char buf = 0;
|
||||
int iovc = 0;
|
||||
for (iovc = 0; iovc != iovcnt; ++iovc) {
|
||||
unsigned char *src = iov[iovc].iov_base;
|
||||
size_t cnt = iov[iovc].iov_len;
|
||||
for (; cnt; --cnt, ++src) {
|
||||
switch (place) {
|
||||
case 0:
|
||||
*dst++ = symbols[*src >> 2];
|
||||
buf = (*src << 4) & 0x3f;
|
||||
place = 1;
|
||||
break;
|
||||
case 1:
|
||||
*dst++ = symbols[(*src >> 4) | buf];
|
||||
buf = (*src << 2) & 0x3f;
|
||||
place = 2;
|
||||
break;
|
||||
case 2:
|
||||
*dst++ = symbols[(*src >> 6) | buf];
|
||||
*dst++ = symbols[*src & 0x3f];
|
||||
place = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (place)
|
||||
*dst++ = symbols[buf];
|
||||
switch (place) {
|
||||
case 1:
|
||||
*dst++ = symbols[64];
|
||||
case 2:
|
||||
*dst++ = symbols[64];
|
||||
}
|
||||
return dst - dstBase64;
|
||||
}
|
||||
|
||||
size_t base64_encodev(char *dstBase64, const struct iovec *const iov, int const iovcnt)
|
||||
{
|
||||
return _base64_encodev(base64_symbols, dstBase64, iov, iovcnt);
|
||||
}
|
||||
|
||||
size_t base64url_encodev(char *dstBase64, const struct iovec *const iov, int const iovcnt)
|
||||
{
|
||||
return _base64_encodev(base64url_symbols, dstBase64, iov, iovcnt);
|
||||
}
|
||||
|
||||
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(base64_symbols, dstBase64, &iov, 1);
|
||||
}
|
||||
|
||||
size_t base64url_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(base64url_symbols, dstBase64, &iov, 1);
|
||||
}
|
||||
|
||||
char *to_base64_str(char *const dstBase64, const unsigned char *srcBinary, size_t srcBytes)
|
||||
{
|
||||
dstBase64[base64_encode(dstBase64, srcBinary, srcBytes)] = '\0';
|
||||
return dstBase64;
|
||||
}
|
||||
|
||||
char *to_base64url_str(char *const dstBase64, const unsigned char *srcBinary, size_t srcBytes)
|
||||
{
|
||||
dstBase64[base64url_encode(dstBase64, srcBinary, srcBytes)] = '\0';
|
||||
return dstBase64;
|
||||
}
|
||||
|
||||
static size_t _base64_decode(unsigned char *dstBinary, size_t dstsiz, const char *const srcBase64, size_t srclen,
|
||||
const char **afterp, int flags, int (*skip_pred)(int),
|
||||
int (*isdigit_pred)(int), int (*ispad_pred)(int), uint8_t (*todigit)(char)
|
||||
)
|
||||
{
|
||||
uint8_t buf = 0;
|
||||
size_t digits = 0;
|
||||
unsigned pads = 0;
|
||||
size_t bytes = 0;
|
||||
const char *const srcend = srcBase64 + srclen;
|
||||
const char *src = srcBase64;
|
||||
const char *first_pad = NULL;
|
||||
for (; srclen == 0 || (src < srcend); ++src) {
|
||||
int isdigit = isdigit_pred(*src);
|
||||
int ispad = ispad_pred(*src);
|
||||
if (!isdigit && !ispad && skip_pred && skip_pred(*src))
|
||||
continue;
|
||||
assert(pads <= 2);
|
||||
if (pads == 2)
|
||||
break;
|
||||
int place = digits & 3;
|
||||
if (pads == 1) {
|
||||
if (place == 3)
|
||||
break;
|
||||
assert(place == 2);
|
||||
if (ispad) {
|
||||
++pads;
|
||||
continue; // consume trailing space before ending
|
||||
}
|
||||
// If only one pad character was present but there should be two, then don't consume the first
|
||||
// one.
|
||||
assert(first_pad != NULL);
|
||||
src = first_pad;
|
||||
break;
|
||||
}
|
||||
assert(pads == 0);
|
||||
if (ispad && place >= 2) {
|
||||
first_pad = src;
|
||||
++pads;
|
||||
continue;
|
||||
}
|
||||
if (!isdigit)
|
||||
break;
|
||||
++digits;
|
||||
if (dstBinary && bytes < dstsiz) {
|
||||
uint8_t d = todigit(*src);
|
||||
switch (place) {
|
||||
case 0:
|
||||
buf = d << 2;
|
||||
break;
|
||||
case 1:
|
||||
dstBinary[bytes++] = buf | (d >> 4);
|
||||
buf = d << 4;
|
||||
break;
|
||||
case 2:
|
||||
dstBinary[bytes++] = buf | (d >> 2);
|
||||
buf = d << 6;
|
||||
break;
|
||||
case 3:
|
||||
dstBinary[bytes++] = buf | d;
|
||||
break;
|
||||
}
|
||||
} else if (flags & B64_CONSUME_ALL) {
|
||||
switch (place) {
|
||||
case 1: case 2: case 3: ++bytes;
|
||||
}
|
||||
} else
|
||||
break;
|
||||
}
|
||||
if (afterp)
|
||||
*afterp = src;
|
||||
else if (*src)
|
||||
return 0;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
size_t base64_decode(unsigned char *dstBinary, size_t dstsiz, const char *const srcBase64, size_t srclen,
|
||||
const char **afterp, int flags, int (*skip_pred)(int))
|
||||
{
|
||||
return _base64_decode(dstBinary, dstsiz, srcBase64, srclen, afterp, flags, skip_pred, is_base64_digit, is_base64_pad, base64_digit);
|
||||
}
|
||||
|
||||
|
||||
size_t base64url_decode(unsigned char *dstBinary, size_t dstsiz, const char *const srcBase64, size_t srclen,
|
||||
const char **afterp, int flags, int (*skip_pred)(int))
|
||||
{
|
||||
return _base64_decode(dstBinary, dstsiz, srcBase64, srclen, afterp, flags, skip_pred, is_base64url_digit, is_base64url_pad, base64url_digit);
|
||||
}
|
||||
|
||||
|
||||
#define _B64 _SERVAL_CTYPE_0_BASE64
|
||||
#define _B64U _SERVAL_CTYPE_0_BASE64URL
|
||||
|
||||
|
75
str.h
75
str.h
@ -130,80 +130,6 @@ int fromhexstrn(unsigned char *dstBinary, size_t nbinary, const char *srcHex, si
|
||||
*/
|
||||
size_t strn_fromhex(unsigned char *dstBinary, ssize_t dstsiz, const char *src, const char **afterp);
|
||||
|
||||
/* -------------------- Base64 encoding and decoding -------------------- */
|
||||
|
||||
/* Return the number of bytes required to represent 'binaryBytes' bytes of binary data encoded
|
||||
* into Base64 form.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
#define BASE64_ENCODED_LEN(binaryBytes) (((size_t)(binaryBytes) + 2) / 3 * 4)
|
||||
|
||||
/* Array of encoding symbols. Entry [64] is the pad character (usually '=').
|
||||
*/
|
||||
extern const char base64_symbols[65];
|
||||
extern const char base64url_symbols[65];
|
||||
|
||||
/* Encode 'srcBytes' bytes of binary data at 'srcBinary' into Base64 representation at 'dstBase64'
|
||||
* (or Base64-URL representation at 'dstBase64url'), 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.
|
||||
*
|
||||
* 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>
|
||||
*/
|
||||
size_t base64_encode(char *dstBase64, const unsigned char *srcBinary, size_t srcBytes);
|
||||
size_t base64url_encode(char *dstBase64url, const unsigned char *srcBinary, size_t srcBytes);
|
||||
struct iovec;
|
||||
size_t base64_encode(char *dstBase64, const unsigned char *srcBinary, size_t srcBytes);
|
||||
size_t base64url_encodev(char *dstBase64url, const struct iovec *iov, int iovcnt);
|
||||
|
||||
/* The same as base64_encode() but appends a terminating NUL character to the encoded string,
|
||||
* so 'dstBase64' must point to at least 'BASE64_ENCODED_LEN(srcBytes) + 1' bytes.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
char *to_base64_str(char *dstBase64, const unsigned char *srcBinary, size_t srcBytes);
|
||||
char *to_base64url_str(char *dstBase64url, const unsigned char *srcBinary, size_t srcBytes);
|
||||
|
||||
#define alloca_base64(buf,len) to_base64_str(alloca(BASE64_ENCODED_LEN(len) + 1), (buf), (len))
|
||||
#define alloca_base64url(buf,len) to_base64url_str(alloca(BASE64_ENCODED_LEN(len) + 1), (buf), (len))
|
||||
|
||||
/* Decode the string at 'srcBase64' as ASCII Base64 or Base64-URL (as per RFC-4648), writing up to
|
||||
* 'dstsiz' decoded binary bytes at 'dstBinary'. Returns the number of decoded binary bytes
|
||||
* produced. If 'dstsiz' is zero or 'dstBinary' is NULL, no binary bytes are produced and returns
|
||||
* zero.
|
||||
*
|
||||
* If the 'afterp' pointer is not NULL, then sets *afterp to point to the first character in
|
||||
* 'srcBase64' where decoding stopped for whatever reason.
|
||||
*
|
||||
* If 'srclen' is 0, then the string at 'stcBase64' is assumed to be NUL-terminated, and decoding
|
||||
* runs until the first non-Base64-digit is encountered. If 'srclen' is nonzero, then decoding will
|
||||
* cease at the first non-Base64-digit or when 'srclen' bytes at 'srcBase64' have been decoded,
|
||||
* whichever comes first.
|
||||
*
|
||||
* If 'skip_pred' is not NULL, then all leading, internal and trailing characters C which are not a
|
||||
* valid Base64 digit or pad '=' will be skipped if skip_pred(C) returns true. Otherwise, decoding
|
||||
* ends at C.
|
||||
*
|
||||
* If the B64_CONSUME_ALL flag is set, then once the 'dstsiz' limit is reached (or if 'dstBinary' is
|
||||
* NULL), the Base64 decoding process continues without actually writing decoded bytes, but instead
|
||||
* counts them and advances through the 'srcBase64' buffer as usual. The return value is then the
|
||||
* number of binary bytes that would be decoded were all available Base64 decoded from 'srcBase64',
|
||||
* and *afterp points to the first character beyond the end of the decoded source characters.
|
||||
*
|
||||
* @author Andrew Bettison <andrew@servalproject.com>
|
||||
*/
|
||||
size_t base64_decode(unsigned char *dstBinary, size_t dstsiz, const char *const srcBase64, size_t srclen,
|
||||
const char **afterp, int flags, int (*skip_pred)(int));
|
||||
size_t base64url_decode(unsigned char *dstBinary, size_t dstsiz, const char *const srcBase64url, size_t srclen,
|
||||
const char **afterp, int flags, int (*skip_pred)(int));
|
||||
|
||||
#define B64_CONSUME_ALL (1 << 0)
|
||||
|
||||
/* -------------------- Character classes -------------------- */
|
||||
|
||||
#define _SERVAL_CTYPE_0_BASE64_MASK 0x3f
|
||||
@ -437,6 +363,7 @@ char *str_str(char *haystack, const char *needle, size_t haystack_len);
|
||||
size_t uri_encode(char *const dstUrienc, ssize_t dstsiz, const char *src, size_t srclen, const char **afterp);
|
||||
size_t www_form_uri_encode(char *const dstUrienc, ssize_t dstsiz, const char *src, size_t srclen, const char **afterp);
|
||||
|
||||
struct iovec;
|
||||
size_t uri_encodev(char *const dstUrienc, ssize_t dstsiz, struct iovec **iovp, int *iovcntp); // modifies *iovp, (*iovp)[...] and *iovcntp
|
||||
size_t www_form_uri_encodev(char *const dstUrienc, ssize_t dstsiz, struct iovec **iovp, int *iovcntp); // modifies *iovp, (*iovp)[...] and *iovcntp
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user