[svn-upgrade] Integrating new upstream version, iodine (0.4.1)
[debian/iodine.git] / src / base32.c
index 73576045606e72d644f515c7626b423c0d6715b1..d42c5e97a5602a7ec1698b0307cf44e26cd0a937 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>
+ * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #include <stdlib.h>
 #include <string.h>
 
+#include "encoding.h"
 #include "base32.h"
 
 static const char cb32[] = 
        "abcdefghijklmnopqrstuvwxyz0123456789";
+static unsigned char rev32[128];
+static int reverse_init = 0;
+
+static struct encoder base32_encoder =
+{
+       "BASE32",
+       base32_encode,
+       base32_decode,
+       base32_handles_dots,
+       base32_handles_dots
+};
+
+struct encoder
+*get_base32_encoder()
+{
+       return &base32_encoder;
+}
+
+int 
+base32_handles_dots()
+{
+       return 0;
+}
 
 int 
-base32_encode(char **buf, size_t *buflen, const void *data, size_t size)
+base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
 {
        size_t newsize;
-       char *newbuf;
-       char *s;
-       char *p;
-       char *q;
+       size_t maxsize;
+       unsigned char *s;
+       unsigned char *p;
+       unsigned char *q;
        int i;
 
-       newsize = 8 * (size / 5 + 1) + 1;
-       if (newsize > *buflen) {
-               if ((newbuf = realloc(*buf, newsize)) == NULL) {
-                       free(*buf);
-                       *buf = NULL;
-                       *buflen = 0;
-                       return 0;
-               }
+       memset(buf, 0, *buflen);
 
-               *buf = newbuf;
-               *buflen = newsize;
+       /* how many chars can we encode within the buf */
+       maxsize = 5 * (*buflen / 8 - 1) - 1;
+       /* how big will the encoded data be */
+       newsize = 8 * (size / 5 + 1) + 1;
+       /* if the buffer is too small, eat some of the data */
+       if (*buflen < newsize) {
+               size = maxsize;
        }
 
-       p = s = *buf;
-       q = (char*)data;
+       p = s = (unsigned char *) buf;
+       q = (unsigned char *)data;
 
        for(i=0;i<size;i+=5) {
-               p[0] = cb32[(q[0] >> 3)];
-               p[1] = cb32[((q[0] & 0x07) << 2) | ((q[1] & 0xc0) >> 6)];
+               p[0] = cb32[((q[0] & 0xf8) >> 3)];
+               p[1] = cb32[(((q[0] & 0x07) << 2) | ((q[1] & 0xc0) >> 6))];
                p[2] = (i+1 < size) ? cb32[((q[1] & 0x3e) >> 1)] : '\0';
                p[3] = (i+1 < size) ? cb32[((q[1] & 0x01) << 4) | ((q[2] & 0xf0) >> 4)] : '\0';
                p[4] = (i+2 < size) ? cb32[((q[2] & 0x0f) << 1) | ((q[3] & 0x80) >> 7)] : '\0';
-               p[5] = (i+3 < size) ? cb32[((q[3] & 0x3e) >> 2)] : '\0';
-               p[6] = (i+3 < size) ? cb32[((q[3] & 0x03) << 3) | ((q[4] & 0xe0) > 5)] : '\0';
+               p[5] = (i+3 < size) ? cb32[((q[3] & 0x7c) >> 2)] : '\0';
+               p[6] = (i+3 < size) ? cb32[((q[3] & 0x03) << 3) | ((q[4] & 0xe0) >> 5)] : '\0';
                p[7] = (i+4 < size) ? cb32[((q[4] & 0x1f))] : '\0';
                
                q += 5;
                p += 8;
        }       
        *p = 0;
-       return strlen(s);
-}
 
-#define DECODE_ERROR 0xffffffff
+       /* store number of bytes from data that was used */
+       *buflen = size;
 
-static int
-pos(char c)
-{
-    const char *p;
-    for (p = cb32; *p; p++)
-               if (*p == c)
-                       return p - cb32;
-    return -1;
+       return strlen(buf) - 1;
 }
 
+#define DECODE_ERROR 0xffffffff
+#define REV32(x) rev32[(int) (x)]
+
 static int
-decode_token(const char *t, char *data
+decode_token(const unsigned char *t, unsigned char *data, size_t len
 {
-       int len;
-
-       len = strlen(t);
-
        if (len < 2)
                return 0;
 
-       data[0] = ((pos(t[0]) & 0x1f) << 3) | 
-                         ((pos(t[1]) & 0x1c) >> 2);
+       data[0] = ((REV32(t[0]) & 0x1f) << 3) | 
+                         ((REV32(t[1]) & 0x1c) >> 2);
        
        if (len < 4)
                return 1;
 
-       data[1] = ((pos(t[1]) & 0x03) << 6) | 
-                         ((pos(t[2]) & 0x1f) << 1) | 
-                         ((pos(t[3]) & 0x10) >> 4);
+       data[1] = ((REV32(t[1]) & 0x03) << 6) | 
+                         ((REV32(t[2]) & 0x1f) << 1) | 
+                         ((REV32(t[3]) & 0x10) >> 4);
 
        if (len < 5)
                return 2;
 
-       data[2] = ((pos(t[3]) & 0x0f) << 4) |
-                         ((pos(t[4]) & 0x1e) >> 1);
+       data[2] = ((REV32(t[3]) & 0x0f) << 4) |
+                         ((REV32(t[4]) & 0x1e) >> 1);
 
        if (len < 7)
                return 3;
 
-       data[3] = ((pos(t[4]) & 0x01) << 7) |
-                         ((pos(t[5]) & 0x1f) << 2) |
-                         ((pos(t[6]) & 0x18) >> 3);
+       data[3] = ((REV32(t[4]) & 0x01) << 7) |
+                         ((REV32(t[5]) & 0x1f) << 2) |
+                         ((REV32(t[6]) & 0x18) >> 3);
 
        if (len < 8)
                return 4;
 
-       data[4] = ((pos(t[6]) & 0x07) << 5) |
-                         ((pos(t[7]) & 0x1f));
+       data[4] = ((REV32(t[6]) & 0x07) << 5) |
+                         ((REV32(t[7]) & 0x1f));
 
        return 5;
 }
 
 int
-base32_decode(void **buf, size_t *buflen, const char *str)
+base32_decode(void *buf, size_t *buflen, const char *str, size_t slen)
 {
        unsigned char *q;
        size_t newsize;
+       size_t maxsize;
        const char *p;
-       char *newbuf;
+       unsigned char c;
        int len;
-       
-       newsize = 5 * (strlen(str) / 8 + 1) + 1;
-       if (newsize > *buflen) {
-               if ((newbuf = realloc(*buf, newsize)) == NULL) {
-                       free(*buf);
-                       *buf = NULL;
-                       *buflen = 0;
-                       return 0;
-               }
+       int i;
 
-               *buf = newbuf;
-               *buflen = newsize;
+       if (!reverse_init) {
+               for (i = 0; i < 32; i++) {
+                       c = cb32[i];
+                       rev32[(int) c] = i;
+               }
+               reverse_init = 1;
+       }
+       
+       /* chars needed to decode slen */
+       newsize = 5 * (slen / 8 + 1) + 1;
+       /* encoded chars that fit in buf */
+       maxsize = 8 * (*buflen / 5 + 1) + 1;
+       /* if the buffer is too small, eat some of the data */
+       if (*buflen < newsize) {
+               slen = maxsize;
        }
 
-       q = *buf;
+       q = buf;
        for (p = str; *p && strchr(cb32, *p); p += 8) {
-               len = decode_token(p, (char *) q);      
+               len = decode_token((unsigned char *) p, (unsigned char *) q, slen);     
                q += len;
+               slen -= 8;
                
                if (len < 5)
                        break;
        }
        *q = '\0';
        
-       return q - (unsigned char *) *buf;
+       return q - (unsigned char *) buf;
 }