Make hexadecimal and base64 routines behave the same.
authorGuus Sliepen <guus@tinc-vpn.org>
Tue, 12 Jul 2011 20:54:49 +0000 (22:54 +0200)
committerGuus Sliepen <guus@tinc-vpn.org>
Tue, 12 Jul 2011 21:23:26 +0000 (23:23 +0200)
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
src/utils.h

index c58f8ca8ddd9857d8c35a00c99f633dcd4624596..ab426ab7e7b3715d83beca1b1ee2bbeed991ccf1 100644 (file)
@@ -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)
index 4e0b55fc58f0515ae979f45f5c9c841b150f088c..648a60717a0e9c8bd1ce6c931d9783076dab182d 100644 (file)
 #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);