[svn-upgrade] Integrating new upstream version, iodine (0.4.0)
[debian/iodine.git] / src / base32.c
1 /*
2  * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #include "base32.h"
22
23 static const char cb32[] = 
24         "abcdefghijklmnopqrstuvwxyz0123456789";
25
26 int 
27 base32_encode(char **buf, size_t *buflen, const void *data, size_t size)
28 {
29         size_t newsize;
30         char *newbuf;
31         char *s;
32         char *p;
33         char *q;
34         int i;
35
36         newsize = 8 * (size / 5 + 1) + 1;
37         if (newsize > *buflen) {
38                 if ((newbuf = realloc(*buf, newsize)) == NULL) {
39                         free(*buf);
40                         *buf = NULL;
41                         *buflen = 0;
42                         return 0;
43                 }
44
45                 *buf = newbuf;
46                 *buflen = newsize;
47         }
48
49         p = s = *buf;
50         q = (char*)data;
51
52         for(i=0;i<size;i+=5) {
53                 p[0] = cb32[(q[0] >> 3)];
54                 p[1] = cb32[((q[0] & 0x07) << 2) | ((q[1] & 0xc0) >> 6)];
55                 p[2] = (i+1 < size) ? cb32[((q[1] & 0x3e) >> 1)] : '\0';
56                 p[3] = (i+1 < size) ? cb32[((q[1] & 0x01) << 4) | ((q[2] & 0xf0) >> 4)] : '\0';
57                 p[4] = (i+2 < size) ? cb32[((q[2] & 0x0f) << 1) | ((q[3] & 0x80) >> 7)] : '\0';
58                 p[5] = (i+3 < size) ? cb32[((q[3] & 0x3e) >> 2)] : '\0';
59                 p[6] = (i+3 < size) ? cb32[((q[3] & 0x03) << 3) | ((q[4] & 0xe0) > 5)] : '\0';
60                 p[7] = (i+4 < size) ? cb32[((q[4] & 0x1f))] : '\0';
61                 
62                 q += 5;
63                 p += 8;
64         }       
65         *p = 0;
66         return strlen(s);
67 }
68
69 #define DECODE_ERROR 0xffffffff
70
71 static int
72 pos(char c)
73 {
74     const char *p;
75     for (p = cb32; *p; p++)
76                 if (*p == c)
77                         return p - cb32;
78     return -1;
79 }
80
81 static int
82 decode_token(const char *t, char *data) 
83 {
84         int len;
85
86         len = strlen(t);
87
88         if (len < 2)
89                 return 0;
90
91         data[0] = ((pos(t[0]) & 0x1f) << 3) | 
92                           ((pos(t[1]) & 0x1c) >> 2);
93         
94         if (len < 4)
95                 return 1;
96
97         data[1] = ((pos(t[1]) & 0x03) << 6) | 
98                           ((pos(t[2]) & 0x1f) << 1) | 
99                           ((pos(t[3]) & 0x10) >> 4);
100
101         if (len < 5)
102                 return 2;
103
104         data[2] = ((pos(t[3]) & 0x0f) << 4) |
105                           ((pos(t[4]) & 0x1e) >> 1);
106
107         if (len < 7)
108                 return 3;
109
110         data[3] = ((pos(t[4]) & 0x01) << 7) |
111                           ((pos(t[5]) & 0x1f) << 2) |
112                           ((pos(t[6]) & 0x18) >> 3);
113
114         if (len < 8)
115                 return 4;
116
117         data[4] = ((pos(t[6]) & 0x07) << 5) |
118                           ((pos(t[7]) & 0x1f));
119
120         return 5;
121 }
122
123 int
124 base32_decode(void **buf, size_t *buflen, const char *str)
125 {
126         unsigned char *q;
127         size_t newsize;
128         const char *p;
129         char *newbuf;
130         int len;
131         
132         newsize = 5 * (strlen(str) / 8 + 1) + 1;
133         if (newsize > *buflen) {
134                 if ((newbuf = realloc(*buf, newsize)) == NULL) {
135                         free(*buf);
136                         *buf = NULL;
137                         *buflen = 0;
138                         return 0;
139                 }
140
141                 *buf = newbuf;
142                 *buflen = newsize;
143         }
144
145         q = *buf;
146         for (p = str; *p && strchr(cb32, *p); p += 8) {
147                 len = decode_token(p, (char *) q);      
148                 q += len;
149                 
150                 if (len < 5)
151                         break;
152         }
153         *q = '\0';
154         
155         return q - (unsigned char *) *buf;
156 }
157