From 06b8271ed5d56c9bd3de459d95907d0ef4f0ea3c Mon Sep 17 00:00:00 2001 From: Guus Sliepen Date: Tue, 12 Jul 2011 22:54:49 +0200 Subject: [PATCH] Make hexadecimal and base64 routines behave the same. The length parameter for the encoding functions is the length of the binary input, and for the decoding functions it is the maximum size of the binary output. The return value is always the length of the resulting output, excluding the terminating NULL character for the encoding routines. All functions can encode and decode in-place. The encoding functions will always write a terminating NULL character, and the decoding functions will stop at a NULL character. --- src/utils.c | 86 ++++++++++++++++++++++++++++++----------------------- src/utils.h | 8 ++--- 2 files changed, 53 insertions(+), 41 deletions(-) diff --git a/src/utils.c b/src/utils.c index c58f8ca..ab426ab 100644 --- a/src/utils.c +++ b/src/utils.c @@ -46,25 +46,29 @@ static int charb64decode(char c) { return 63; } -void hex2bin(char *src, char *dst, int length) { +int hex2bin(char *src, char *dst, int length) { int i; - for(i = 0; i < length; i++) + for(i = 0; i < length && src[i * 2] && src[i * 2 + 1]; i++) dst[i] = charhex2bin(src[i * 2]) * 16 + charhex2bin(src[i * 2 + 1]); + return i; } -void bin2hex(char *src, char *dst, int length) { +int bin2hex(char *src, char *dst, int length) { int i; for(i = length - 1; i >= 0; i--) { dst[i * 2 + 1] = hexadecimals[(unsigned char) src[i] & 15]; dst[i * 2] = hexadecimals[(unsigned char) src[i] >> 4]; } + dst[length * 2] = 0; + return length * 2; } -int b64decode(const char *src, char *dst, int length) { +int b64decode(char *src, char *dst, int length) { + int i; uint32_t triplet = 0; unsigned char *udst = dst; - for(int i = 0; i < length; i++) { + for(i = 0; i < length / 3 * 4 && src[i]; i++) { triplet |= charb64decode(src[i]) << (6 * (i & 3)); if((i & 3) == 3) { udst[0] = triplet & 0xff; triplet >>= 8; @@ -74,49 +78,57 @@ int b64decode(const char *src, char *dst, int length) { udst += 3; } } - if((length & 3) == 3) { + if((i & 3) == 3) { udst[0] = triplet & 0xff; triplet >>= 8; udst[1] = triplet & 0xff; - return length / 4 * 3 + 2; - } else if((length & 3) == 2) { + return i / 4 * 3 + 2; + } else if((i & 3) == 2) { udst[0] = triplet & 0xff; - return length / 4 * 3 + 1; + return i / 4 * 3 + 1; } else { - return length / 4 * 3; + return i / 4 * 3; } } -int b64encode(const char *src, char *dst, int length) { +int b64encode(char *src, char *dst, int length) { uint32_t triplet; const unsigned char *usrc = src; - int origlen = length; - - while(length > 0) { - if(length >= 3) { - triplet = usrc[0] | usrc[1] << 8 | usrc[2] << 16; - dst[0] = base64imals[triplet & 63]; triplet >>= 6; - dst[1] = base64imals[triplet & 63]; triplet >>= 6; - dst[2] = base64imals[triplet & 63]; triplet >>= 6; - dst[3] = base64imals[triplet]; - dst += 4; usrc += 3; length -= 3; - } else if(length >=2) { - triplet = usrc[0] | usrc[1] << 8; - dst[0] = base64imals[triplet & 63]; triplet >>= 6; - dst[1] = base64imals[triplet & 63]; triplet >>= 6; - dst[2] = base64imals[triplet]; - dst[3] = 0; - return origlen / 3 * 4 + 3; - } else { - triplet = usrc[0]; - dst[0] = base64imals[triplet & 63]; triplet >>= 6; - dst[1] = base64imals[triplet]; - dst[2] = 0; - return origlen / 3 * 4 + 2; - } + int si = length / 3 * 3; + int di = length / 3 * 4; + + switch(length % 3) { + case 2: + triplet = usrc[si] | usrc[si + 1] << 8; + dst[di] = base64imals[triplet & 63]; triplet >>= 6; + dst[di + 1] = base64imals[triplet & 63]; triplet >>= 6; + dst[di + 2] = base64imals[triplet]; + dst[di + 3] = 0; + length = di + 2; + break; + case 1: + triplet = usrc[si]; + dst[di] = base64imals[triplet & 63]; triplet >>= 6; + dst[di + 1] = base64imals[triplet]; + dst[di + 2] = 0; + length = di + 1; + break; + default: + dst[di] = 0; + length = di; + break; + } + + while(si > 0) { + di -= 4; + si -= 3; + triplet = usrc[si] | usrc[si + 1] << 8 | usrc[si + 2] << 16; + dst[di] = base64imals[triplet & 63]; triplet >>= 6; + dst[di + 1] = base64imals[triplet & 63]; triplet >>= 6; + dst[di + 2] = base64imals[triplet & 63]; triplet >>= 6; + dst[di + 3] = base64imals[triplet]; } - *dst = 0; - return origlen / 4 * 3; + return length; } #if defined(HAVE_MINGW) || defined(HAVE_CYGWIN) diff --git a/src/utils.h b/src/utils.h index 4e0b55f..648a607 100644 --- a/src/utils.h +++ b/src/utils.h @@ -21,11 +21,11 @@ #ifndef __TINC_UTILS_H__ #define __TINC_UTILS_H__ -extern void hex2bin(char *src, char *dst, int length); -extern void bin2hex(char *src, char *dst, int length); +extern int hex2bin(char *src, char *dst, int length); +extern int bin2hex(char *src, char *dst, int length); -extern int b64encode(const char *src, char *dst, int length); -extern int b64decode(const char *src, char *dst, int length); +extern int b64encode(char *src, char *dst, int length); +extern int b64decode(char *src, char *dst, int length); #ifdef HAVE_MINGW extern const char *winerror(int); -- 2.25.1