[svn-upgrade] Integrating new upstream version, iodine (0.5.1)
[debian/iodine.git] / src / base64.c
1 /*
2  * Copyright (c) 2006-2009 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@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 "encoding.h"
22 #include "common.h"
23 #include "base64.h"
24
25 #define BLKSIZE_RAW 3
26 #define BLKSIZE_ENC 4
27
28 static const char cb64[] = 
29         "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789+";
30 static unsigned char rev64[128];
31 static int reverse_init = 0;
32
33 static int base64_encode(char *, size_t *, const void *, size_t);
34 static int base64_decode(void *, size_t *, const char *, size_t);
35 static int base64_handles_dots();
36 static int base64_blksize_raw();
37 static int base64_blksize_enc();
38
39 #define REV64(x) rev64[(int) (x)]
40
41 static struct encoder base64_encoder =
42 {
43         "Base64",
44         base64_encode,
45         base64_decode,
46         base64_handles_dots,
47         base64_handles_dots,
48         base64_blksize_raw,
49         base64_blksize_enc
50 };
51
52 struct encoder
53 *get_base64_encoder()
54 {
55         return &base64_encoder;
56 }
57
58 static int 
59 base64_handles_dots()
60 {
61         return 0;
62 }
63
64 static int 
65 base64_blksize_raw()
66 {
67         return BLKSIZE_RAW;
68 }
69
70 static int 
71 base64_blksize_enc()
72 {
73         return BLKSIZE_ENC;
74 }
75
76 static int 
77 base64_encode(char *buf, size_t *buflen, const void *data, size_t size)
78 {
79         size_t newsize;
80         size_t maxsize;
81         unsigned char *s;
82         unsigned char *p;
83         unsigned char *q;
84         int i;
85
86         memset(buf, 0, *buflen);
87         
88         /* how many chars can we encode within the buf */
89         maxsize = BLKSIZE_RAW * (*buflen / BLKSIZE_ENC);
90         /* how big will the encoded data be */
91         newsize = BLKSIZE_ENC * (size / BLKSIZE_RAW);
92         if (size % BLKSIZE_RAW) {
93                 newsize += BLKSIZE_ENC;
94         }
95
96         /* if the buffer is too small, eat some of the data */
97         if (*buflen < newsize) {
98                 size = maxsize;
99         }
100
101         p = s = (unsigned char *) buf;
102         q = (unsigned char *)data;
103
104         for(i=0;i<size;i+=BLKSIZE_RAW) {
105                 p[0] = cb64[((q[0] & 0xfc) >> 2)];
106                 p[1] = cb64[(((q[0] & 0x03) << 4) | ((q[1] & 0xf0) >> 4))];
107                 p[2] = (i+1 < size) ? cb64[((q[1] & 0x0f) << 2 ) | ((q[2] & 0xc0) >> 6)] : '\0';
108                 p[3] = (i+2 < size) ? cb64[(q[2] & 0x3f)] : '\0';
109                 
110                 q += BLKSIZE_RAW;
111                 p += BLKSIZE_ENC;
112         }       
113         *p = 0;
114
115         /* store number of bytes from data that was used */
116         *buflen = size;
117
118         return strlen(buf);
119 }
120
121 #define DECODE_ERROR 0xffffffff
122
123 static int
124 decode_token(const unsigned char *t, unsigned char *data, size_t len) 
125 {
126         if (len < 2)
127                 return 0;
128
129         data[0] = ((REV64(t[0]) & 0x3f) << 2) | 
130                           ((REV64(t[1]) & 0x30) >> 4);
131
132         if (len < 3)
133                 return 1;
134
135         data[1] = ((REV64(t[1]) & 0x0f) << 4) | 
136                           ((REV64(t[2]) & 0x3c) >> 2);
137
138         if (len < 4)
139                 return 2;
140
141         data[2] = ((REV64(t[2]) & 0x03) << 6) |
142                           (REV64(t[3]) & 0x3f);
143
144         return 3;
145 }
146
147 static int
148 base64_decode(void *buf, size_t *buflen, const char *str, size_t slen)
149 {
150         unsigned char *q;
151         size_t newsize;
152         size_t maxsize;
153         const char *p;
154         unsigned char c;
155         unsigned char block[BLKSIZE_ENC];
156         int len;
157         int i;
158
159         if (!reverse_init) {
160                 for (i = 0; i < 64; i++) {
161                         c = cb64[i];
162                         rev64[(int) c] = i;
163                 }
164                 reverse_init = 1;
165         }
166         
167         /* chars needed to decode slen */
168         newsize = BLKSIZE_RAW * (slen / BLKSIZE_ENC + 1) + 1;
169         /* encoded chars that fit in buf */
170         maxsize = BLKSIZE_ENC * (*buflen / BLKSIZE_RAW + 1) + 1;
171         /* if the buffer is too small, eat some of the data */
172         if (*buflen < newsize) {
173                 slen = maxsize;
174         }
175         
176
177         q = buf;
178         for (p = str; *p; p += BLKSIZE_ENC) {
179                 /* since the str is const, we unescape in another buf */
180                 for (i = 0; i < BLKSIZE_ENC; i++) {
181                         block[i] = p[i];
182                 }
183                 len = decode_token(block, (unsigned char *) q, slen);   
184                 q += len;
185                 slen -= BLKSIZE_ENC;
186                 
187                 if (len < BLKSIZE_RAW)
188                         break;
189         }
190         *q = '\0';
191         
192         return q - (unsigned char *) buf;
193 }
194