2 * Copyright (c) 2006-2007 Bjorn Andersson <flex@kryo.se>, Erik Ekman <yarrick@kryo.se>
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.
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.
25 static const char cb64[] =
26 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-0123456789.";
27 static unsigned char rev64[128];
28 static int reverse_init = 0;
30 #define REV64(x) rev64[(int) (x)]
31 #define MODE (cb64[62])
32 #define P62 (cb64[62])
33 #define P63 (cb64[63])
35 static struct encoder base64_encoder =
47 return &base64_encoder;
57 findesc(int *count, unsigned char *esc, char c1, char c2, char c3, char c4)
62 int num1 = 0xFF; /* a very big number */
63 int num2 = 0xFE; /* a nearly as big number */
67 /* check if no more escapes needed */
68 if (count[62] == 0 && count[63] == 0) {
74 for (i = 0; i < 62; i++) {
75 if (i == c1 || i == c2 || i == c3 || i == c4) {
79 if (count[i] < num1) {
84 } else if (count[i] < num2) {
95 escape_chars(char *buf, size_t buflen)
101 unsigned char temp[4096];
105 unsigned char esc[2];
107 memset(counter, 0, sizeof(counter));
111 /* first, find the number of times each token is used */
112 r = (unsigned char *) buf;
115 counter[REV64(*r)]++;
119 /* check if work needed */
120 if (counter[62] == 0 && counter[63] == 0)
124 w = (unsigned char *) buf;
127 /* check a block for esc chars */
129 if (reset == 0 && escapes == 0 && (
130 r[0] == esc[0] || r[1] == esc[0] ||r[2] == esc[0] ||r[2] == esc[0] ||
131 r[0] == esc[1] || r[1] == esc[1] ||r[2] == esc[1] ||r[2] == esc[1])) {
132 /* last set of escape chars were unused.
133 * if we reset last escape switch then maybe we dont have to switch now */
135 /* change the latest escape switch to 999 (RESET) */
139 /* store default esc chars */
145 /* these two if blocks can not be combined because a block can contain both
146 * char 9 and/or . and the current escape chars. */
147 if (r[0] == esc[0] || r[1] == esc[0] ||r[2] == esc[0] ||r[2] == esc[0] ||
148 r[0] == esc[1] || r[1] == esc[1] ||r[2] == esc[1] ||r[2] == esc[1]) {
149 /* switch escape chars */
153 /* find 2 suitable escape chars */
154 findesc(counter, esc, REV64(r[0]), REV64(r[1]), REV64(r[2]), REV64(r[3]));
156 /* store escape switch position */
159 /* write new escape chars */
165 /* update counter on remaining chars */
166 for (i = 0; i < 4; i++) {
168 counter[REV64(r[i])]--;
171 /* do the escaping */
172 for (i = 0; i < 4; i++) {
176 } else if (r[i] == P63) {
182 /* copy back to buf */
191 base64_encode(char *buf, size_t *buflen, const void *data, size_t size)
201 memset(buf, 0, *buflen);
204 for (i = 0; i < 64; i++) {
211 /* how many chars can we encode within the buf */
212 maxsize = 3 * (*buflen / 4 - 1) - 1;
213 /* how big will the encoded data be */
214 newsize = 4 * (size / 3 + 1) + 1;
215 /* if the buffer is too small, eat some of the data */
216 if (*buflen < newsize) {
220 p = s = (unsigned char *) buf;
221 q = (unsigned char *)data;
223 for(i=0;i<size;i+=3) {
224 p[0] = cb64[((q[0] & 0xfc) >> 2)];
225 p[1] = cb64[(((q[0] & 0x03) << 4) | ((q[1] & 0xf0) >> 4))];
226 p[2] = (i+1 < size) ? cb64[((q[1] & 0x0f) << 2 ) | ((q[2] & 0xc0) >> 6)] : '\0';
227 p[3] = (i+2 < size) ? cb64[(q[2] & 0x3f)] : '\0';
234 escape_chars(buf, *buflen);
236 /* store number of bytes from data that was used */
239 return strlen(buf) - 1;
242 #define DECODE_ERROR 0xffffffff
245 decode_token(const unsigned char *t, unsigned char *data, size_t len)
250 data[0] = ((REV64(t[0]) & 0x3f) << 2) |
251 ((REV64(t[1]) & 0x30) >> 4);
256 data[1] = ((REV64(t[1]) & 0x0f) << 4) |
257 ((REV64(t[2]) & 0x3c) >> 2);
262 data[2] = ((REV64(t[2]) & 0x03) << 6) |
263 (REV64(t[3]) & 0x3f);
269 base64_decode(void *buf, size_t *buflen, const char *str, size_t slen)
276 unsigned char block[4];
277 unsigned char prot62;
278 unsigned char prot63;
283 for (i = 0; i < 64; i++) {
290 /* chars needed to decode slen */
291 newsize = 3 * (slen / 4 + 1) + 1;
292 /* encoded chars that fit in buf */
293 maxsize = 4 * (*buflen / 3 + 1) + 1;
294 /* if the buffer is too small, eat some of the data */
295 if (*buflen < newsize) {
303 for (p = str; *p; p += 4) {
304 /* handle escape instructions */
307 if (p[0] == MODE && p[1] == MODE) {
308 /* reset escape chars */
318 /* since the str is const, we unescape in another buf */
319 for (i = 0; i < 4; i++) {
321 if (prot62 == block[i]) {
323 } else if (prot63 == block[i]) {
327 len = decode_token(block, (unsigned char *) q, slen);
336 return q - (unsigned char *) buf;