Change priority from extra to optional in debian/control.
[debian/iodine.git] / src / base64.c
1 /*
2  * Copyright (c) 2006-2014 Erik Ekman <yarrick@kryo.se>,
3  * 2006-2009 Bjorn Andersson <flex@kryo.se>
4  * Mostly rewritten 2009 J.A.Bezemer@opensourcepartners.nl
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include "encoding.h"
24 #include "base64.h"
25
26 #define BLKSIZE_RAW 3
27 #define BLKSIZE_ENC 4
28
29 /* Note: the "unofficial" char is last here, which means that the \377 pattern
30    in DOWNCODECCHECK1 ('Y' request) will properly test it. */
31 static const char cb64[] =
32         "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789+";
33 static unsigned char rev64[256];
34 static int reverse_init = 0;
35
36 static int base64_encode(char *, size_t *, const void *, size_t);
37 static int base64_decode(void *, size_t *, const char *, size_t);
38 static int base64_handles_dots();
39 static int base64_blksize_raw();
40 static int base64_blksize_enc();
41
42 static struct encoder base64_encoder =
43 {
44         "Base64",
45         base64_encode,
46         base64_decode,
47         base64_handles_dots,
48         base64_handles_dots,
49         base64_blksize_raw,
50         base64_blksize_enc
51 };
52
53 struct encoder
54 *get_base64_encoder()
55 {
56         return &base64_encoder;
57 }
58
59 static int
60 base64_handles_dots()
61 {
62         return 0;
63 }
64
65 static int
66 base64_blksize_raw()
67 {
68         return BLKSIZE_RAW;
69 }
70
71 static int
72 base64_blksize_enc()
73 {
74         return BLKSIZE_ENC;
75 }
76
77 inline static void
78 base64_reverse_init()
79 {
80         int i;
81         unsigned char c;
82
83         if (!reverse_init) {
84                 memset (rev64, 0, 256);
85                 for (i = 0; i < 64; i++) {
86                         c = cb64[i];
87                         rev64[(int) c] = i;
88                 }
89                 reverse_init = 1;
90         }
91 }
92
93 static int
94 base64_encode(char *buf, size_t *buflen, const void *data, size_t size)
95 /*
96  * Fills *buf with max. *buflen characters, encoding size bytes of *data.
97  *
98  * NOTE: *buf space should be at least 1 byte _more_ than *buflen
99  * to hold the trailing '\0'.
100  *
101  * return value    : #bytes filled in buf   (excluding \0)
102  * sets *buflen to : #bytes encoded from data
103  */
104 {
105         unsigned char *udata = (unsigned char *) data;
106         int iout = 0;   /* to-be-filled output char */
107         int iin = 0;    /* one more than last input byte that can be
108                            successfully decoded */
109
110         /* Note: Don't bother to optimize manually. GCC optimizes
111            better(!) when using simplistic array indexing. */
112
113         while (1) {
114                 if (iout >= *buflen || iin >= size)
115                         break;
116                 buf[iout] = cb64[((udata[iin] & 0xfc) >> 2)];
117                 iout++;
118
119                 if (iout >= *buflen || iin >= size) {
120                         iout--;         /* previous char is useless */
121                         break;
122                 }
123                 buf[iout] = cb64[((udata[iin] & 0x03) << 4) |
124                                   ((iin + 1 < size) ?
125                                    ((udata[iin + 1] & 0xf0) >> 4) : 0)];
126                 iin++;                  /* 0 complete, iin=1 */
127                 iout++;
128
129                 if (iout >= *buflen || iin >= size)
130                         break;
131                 buf[iout] = cb64[((udata[iin] & 0x0f) << 2 ) |
132                                   ((iin + 1 < size) ?
133                                    ((udata[iin + 1] & 0xc0) >> 6) : 0)];
134                 iin++;                  /* 1 complete, iin=2 */
135                 iout++;
136
137                 if (iout >= *buflen || iin >= size)
138                         break;
139                 buf[iout] = cb64[(udata[iin] & 0x3f)];
140                 iin++;                  /* 2 complete, iin=3 */
141                 iout++;
142         }
143
144         buf[iout] = '\0';
145
146         /* store number of bytes from data that was used */
147         *buflen = iin;
148
149         return iout;
150 }
151
152 #define REV64(x) rev64[(int) (x)]
153
154 static int
155 base64_decode(void *buf, size_t *buflen, const char *str, size_t slen)
156 /*
157  * Fills *buf with max. *buflen bytes, decoded from slen chars in *str.
158  * Decoding stops early when *str contains \0.
159  * Illegal encoded chars are assumed to decode to zero.
160  *
161  * NOTE: *buf space should be at least 1 byte _more_ than *buflen
162  * to hold a trailing '\0' that is added (though *buf will usually
163  * contain full-binary data).
164  *
165  * return value    : #bytes filled in buf   (excluding \0)
166  */
167 {
168         unsigned char *ubuf = (unsigned char *) buf;
169         int iout = 0;   /* to-be-filled output byte */
170         int iin = 0;    /* next input char to use in decoding */
171
172         base64_reverse_init ();
173
174         /* Note: Don't bother to optimize manually. GCC optimizes
175            better(!) when using simplistic array indexing. */
176
177         while (1) {
178                 if (iout >= *buflen || iin + 1 >= slen ||
179                     str[iin] == '\0' || str[iin + 1] == '\0')
180                         break;
181                 ubuf[iout] = ((REV64(str[iin]) & 0x3f) << 2) |
182                              ((REV64(str[iin + 1]) & 0x30) >> 4);
183                 iin++;                  /* 0 used up, iin=1 */
184                 iout++;
185
186                 if (iout >= *buflen || iin + 1 >= slen ||
187                     str[iin] == '\0' || str[iin + 1] == '\0')
188                         break;
189                 ubuf[iout] = ((REV64(str[iin]) & 0x0f) << 4) |
190                              ((REV64(str[iin + 1]) & 0x3c) >> 2);
191                 iin++;                  /* 1 used up, iin=2 */
192                 iout++;
193
194                 if (iout >= *buflen || iin + 1 >= slen ||
195                     str[iin] == '\0' || str[iin + 1] == '\0')
196                         break;
197                 ubuf[iout] = ((REV64(str[iin]) & 0x03) << 6) |
198                              (REV64(str[iin + 1]) & 0x3f);
199                 iin += 2;               /* 2,3 used up, iin=4 */
200                 iout++;
201         }
202
203         ubuf[iout] = '\0';
204
205         return iout;
206 }