Change priority from extra to optional in debian/control.
[debian/iodine.git] / src / base32.c
index af6a2147ac1fa5cf8a3141f7d1327089801483c0..d971ce25b01f400a5f34ed88c08533ec966ee91e 100644 (file)
@@ -1,5 +1,7 @@
 /*
 /*
- * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
+ * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
+ * 2006-2009 Bjorn Andersson <flex@kryo.se>
+ * Mostly rewritten 2009 J.A.Bezemer@opensourcepartners.nl
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #define BLKSIZE_RAW 5
 #define BLKSIZE_ENC 8
 
 #define BLKSIZE_RAW 5
 #define BLKSIZE_ENC 8
 
-static const char cb32[] = 
+static const char cb32[] =
        "abcdefghijklmnopqrstuvwxyz012345";
        "abcdefghijklmnopqrstuvwxyz012345";
-static unsigned char rev32[128];
+static const char cb32_ucase[] =
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345";
+static unsigned char rev32[256];
 static int reverse_init = 0;
 
 static int reverse_init = 0;
 
-static int base32_decode(void *, size_t *, const char *, size_t);
 static int base32_encode(char *, size_t *, const void *, size_t);
 static int base32_encode(char *, size_t *, const void *, size_t);
+static int base32_decode(void *, size_t *, const char *, size_t);
 static int base32_handles_dots();
 static int base32_blksize_raw();
 static int base32_blksize_enc();
 static int base32_handles_dots();
 static int base32_blksize_raw();
 static int base32_blksize_enc();
@@ -52,169 +56,216 @@ struct encoder
        return &base32_encoder;
 }
 
        return &base32_encoder;
 }
 
-static int 
+static int
 base32_handles_dots()
 {
        return 0;
 }
 
 base32_handles_dots()
 {
        return 0;
 }
 
-static int 
+static int
 base32_blksize_raw()
 {
        return BLKSIZE_RAW;
 }
 
 base32_blksize_raw()
 {
        return BLKSIZE_RAW;
 }
 
-static int 
+static int
 base32_blksize_enc()
 {
        return BLKSIZE_ENC;
 }
 
 base32_blksize_enc()
 {
        return BLKSIZE_ENC;
 }
 
-int
-b32_5to8(int in)
-{
-       return cb32[in & 31];
-}
-
-int
-b32_8to5(int in)
+inline static void
+base32_reverse_init()
 {
        int i;
 {
        int i;
-       int c;
+       unsigned char c;
+
        if (!reverse_init) {
        if (!reverse_init) {
+               memset (rev32, 0, 256);
                for (i = 0; i < 32; i++) {
                        c = cb32[i];
                        rev32[(int) c] = i;
                for (i = 0; i < 32; i++) {
                        c = cb32[i];
                        rev32[(int) c] = i;
+                       c = cb32_ucase[i];
+                       rev32[(int) c] = i;
                }
                reverse_init = 1;
        }
                }
                reverse_init = 1;
        }
-       return rev32[in];
 }
 
 }
 
-static int 
-base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
+int
+b32_5to8(int in)
 {
 {
-       size_t newsize;
-       size_t maxsize;
-       unsigned char *p;
-       unsigned char *q;
-       int i;
-
-       memset(buf, 0, *buflen);
-
-       /* how many chars can we encode within the buf */
-       maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC - 1) - 1;
-       /* how big will the encoded data be */
-       newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW + 1) + 1;
-       /* if the buffer is too small, eat some of the data */
-       if (*buflen < newsize) {
-               size = maxsize;
-       }
-
-       p = (unsigned char *) buf;
-       q = (unsigned char *)data;
-
-       for(i=0;i<size;i+=BLKSIZE_RAW) {
-               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] & 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 += BLKSIZE_RAW;
-               p += BLKSIZE_ENC;
-       }       
-       *p = 0;
-
-       /* store number of bytes from data that was used */
-       *buflen = size;
-
-       return strlen(buf) - 1;
+       return cb32[in & 31];
 }
 
 }
 
-#define DECODE_ERROR 0xffffffff
-#define REV32(x) rev32[(int) (x)]
+int
+b32_8to5(int in)
+{
+       base32_reverse_init();
+       return rev32[in];
+}
 
 static int
 
 static int
-decode_token(const unsigned char *t, unsigned char *data, size_t len) 
+base32_encode(char *buf, size_t *buflen, const void *data, size_t size)
+/*
+ * Fills *buf with max. *buflen characters, encoding size bytes of *data.
+ *
+ * NOTE: *buf space should be at least 1 byte _more_ than *buflen
+ * to hold the trailing '\0'.
+ *
+ * return value    : #bytes filled in buf   (excluding \0)
+ * sets *buflen to : #bytes encoded from data
+ */
 {
 {
-       if (len < 2)
-               return 0;
+       unsigned char *udata = (unsigned char *) data;
+       int iout = 0;   /* to-be-filled output char */
+       int iin = 0;    /* one more than last input byte that can be
+                          successfully decoded */
 
 
-       data[0] = ((REV32(t[0]) & 0x1f) << 3) | 
-                         ((REV32(t[1]) & 0x1c) >> 2);
-       
-       if (len < 4)
-               return 1;
+       /* Note: Don't bother to optimize manually. GCC optimizes
+          better(!) when using simplistic array indexing. */
 
 
-       data[1] = ((REV32(t[1]) & 0x03) << 6) | 
-                         ((REV32(t[2]) & 0x1f) << 1) | 
-                         ((REV32(t[3]) & 0x10) >> 4);
+       while (1) {
+               if (iout >= *buflen || iin >= size)
+                       break;
+               buf[iout] = cb32[((udata[iin] & 0xf8) >> 3)];
+               iout++;
+
+               if (iout >= *buflen || iin >= size) {
+                       iout--;         /* previous char is useless */
+                       break;
+               }
+               buf[iout] = cb32[((udata[iin] & 0x07) << 2) |
+                                 ((iin + 1 < size) ?
+                                  ((udata[iin + 1] & 0xc0) >> 6) : 0)];
+               iin++;                  /* 0 complete, iin=1 */
+               iout++;
+
+               if (iout >= *buflen || iin >= size)
+                       break;
+               buf[iout] = cb32[((udata[iin] & 0x3e) >> 1)];
+               iout++;
 
 
-       if (len < 5)
-               return 2;
+               if (iout >= *buflen || iin >= size) {
+                       iout--;         /* previous char is useless */
+                       break;
+               }
+               buf[iout] = cb32[((udata[iin] & 0x01) << 4) |
+                                 ((iin + 1 < size) ?
+                                  ((udata[iin + 1] & 0xf0) >> 4) : 0)];
+               iin++;                  /* 1 complete, iin=2 */
+               iout++;
+
+               if (iout >= *buflen || iin >= size)
+                       break;
+               buf[iout] = cb32[((udata[iin] & 0x0f) << 1) |
+                                 ((iin + 1 < size) ?
+                                  ((udata[iin + 1] & 0x80) >> 7) : 0)];
+               iin++;                  /* 2 complete, iin=3 */
+               iout++;
 
 
-       data[2] = ((REV32(t[3]) & 0x0f) << 4) |
-                         ((REV32(t[4]) & 0x1e) >> 1);
+               if (iout >= *buflen || iin >= size)
+                       break;
+               buf[iout] = cb32[((udata[iin] & 0x7c) >> 2)];
+               iout++;
 
 
-       if (len < 7)
-               return 3;
+               if (iout >= *buflen || iin >= size) {
+                       iout--;         /* previous char is useless */
+                       break;
+               }
+               buf[iout] = cb32[((udata[iin] & 0x03) << 3) |
+                                 ((iin + 1 < size) ?
+                                  ((udata[iin + 1] & 0xe0) >> 5) : 0)];
+               iin++;                  /* 3 complete, iin=4 */
+               iout++;
 
 
-       data[3] = ((REV32(t[4]) & 0x01) << 7) |
-                         ((REV32(t[5]) & 0x1f) << 2) |
-                         ((REV32(t[6]) & 0x18) >> 3);
+               if (iout >= *buflen || iin >= size)
+                       break;
+               buf[iout] = cb32[((udata[iin] & 0x1f))];
+               iin++;                  /* 4 complete, iin=5 */
+               iout++;
+       }
 
 
-       if (len < 8)
-               return 4;
+       buf[iout] = '\0';
 
 
-       data[4] = ((REV32(t[6]) & 0x07) << 5) |
-                         ((REV32(t[7]) & 0x1f));
+       /* store number of bytes from data that was used */
+       *buflen = iin;
 
 
-       return 5;
+       return iout;
 }
 
 }
 
+#define REV32(x) rev32[(int) (x)]
+
 static int
 base32_decode(void *buf, size_t *buflen, const char *str, size_t slen)
 static int
 base32_decode(void *buf, size_t *buflen, const char *str, size_t slen)
+/*
+ * Fills *buf with max. *buflen bytes, decoded from slen chars in *str.
+ * Decoding stops early when *str contains \0.
+ * Illegal encoded chars are assumed to decode to zero.
+ *
+ * NOTE: *buf space should be at least 1 byte _more_ than *buflen
+ * to hold a trailing '\0' that is added (though *buf will usually
+ * contain full-binary data).
+ *
+ * return value    : #bytes filled in buf   (excluding \0)
+ */
 {
 {
-       unsigned char *q;
-       size_t newsize;
-       size_t maxsize;
-       const char *p;
-       unsigned char c;
-       int len;
-       int i;
+       unsigned char *ubuf = (unsigned char *) buf;
+       int iout = 0;   /* to-be-filled output byte */
+       int iin = 0;    /* next input char to use in decoding */
 
 
-       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 = BLKSIZE_RAW * (slen / BLKSIZE_ENC + 1) + 1;
-       /* encoded chars that fit in buf */
-       maxsize = BLKSIZE_ENC * (*buflen / BLKSIZE_RAW + 1) + 1;
-       /* if the buffer is too small, eat some of the data */
-       if (*buflen < newsize) {
-               slen = maxsize;
-       }
+       base32_reverse_init ();
+
+       /* Note: Don't bother to optimize manually. GCC optimizes
+          better(!) when using simplistic array indexing. */
 
 
-       q = buf;
-       for (p = str; *p && strchr(cb32, *p); p += BLKSIZE_ENC) {
-               len = decode_token((unsigned char *) p, (unsigned char *) q, slen);     
-               q += len;
-               slen -= BLKSIZE_ENC;
-               
-               if (len < BLKSIZE_RAW)
+       while (1) {
+               if (iout >= *buflen || iin + 1 >= slen ||
+                   str[iin] == '\0' || str[iin + 1] == '\0')
+                       break;
+               ubuf[iout] = ((REV32(str[iin]) & 0x1f) << 3) |
+                            ((REV32(str[iin + 1]) & 0x1c) >> 2);
+               iin++;                  /* 0 used up, iin=1 */
+               iout++;
+
+               if (iout >= *buflen || iin + 2 >= slen ||
+                   str[iin] == '\0' || str[iin + 1] == '\0' ||
+                   str[iin + 2] == '\0')
+                       break;
+               ubuf[iout] = ((REV32(str[iin]) & 0x03) << 6) |
+                            ((REV32(str[iin + 1]) & 0x1f) << 1) |
+                            ((REV32(str[iin + 2]) & 0x10) >> 4);
+               iin += 2;               /* 1,2 used up, iin=3 */
+               iout++;
+
+               if (iout >= *buflen || iin + 1 >= slen ||
+                   str[iin] == '\0' || str[iin + 1] == '\0')
                        break;
                        break;
+               ubuf[iout] = ((REV32(str[iin]) & 0x0f) << 4) |
+                            ((REV32(str[iin + 1]) & 0x1e) >> 1);
+               iin++;                  /* 3 used up, iin=4 */
+               iout++;
+
+               if (iout >= *buflen || iin + 2 >= slen ||
+                   str[iin] == '\0' || str[iin + 1] == '\0' ||
+                   str[iin + 2] == '\0')
+                       break;
+               ubuf[iout] = ((REV32(str[iin]) & 0x01) << 7) |
+                            ((REV32(str[iin + 1]) & 0x1f) << 2) |
+                            ((REV32(str[iin + 2]) & 0x18) >> 3);
+               iin += 2;               /* 4,5 used up, iin=6 */
+               iout++;
+
+               if (iout >= *buflen || iin + 1 >= slen ||
+                   str[iin] == '\0' || str[iin + 1] == '\0')
+                       break;
+               ubuf[iout] = ((REV32(str[iin]) & 0x07) << 5) |
+                            ((REV32(str[iin + 1]) & 0x1f));
+               iin += 2;               /* 6,7 used up, iin=8 */
+               iout++;
        }
        }
-       *q = '\0';
-       
-       return q - (unsigned char *) buf;
-}
 
 
+       ubuf[iout] = '\0';
+
+       return iout;
+}