1/*
2 * Copyright (c) 1995-2001 Kungliga Tekniska H��gskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include <config.h>
35
36#include <stdlib.h>
37#include <string.h>
38#include <limits.h>
39#include "base64.h"
40
41static const char base64_chars[] =
42    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
43
44static int
45pos(char c)
46{
47    const char *p;
48    for (p = base64_chars; *p; p++)
49	if (*p == c)
50	    return p - base64_chars;
51    return -1;
52}
53
54ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
55base64_encode(const void *data, int size, char **str)
56{
57    char *s, *p;
58    int i;
59    int c;
60    const unsigned char *q;
61
62    if (size > INT_MAX/4 || size < 0) {
63	*str = NULL;
64	return -1;
65    }
66
67    p = s = (char *) malloc(size * 4 / 3 + 4);
68    if (p == NULL) {
69        *str = NULL;
70	return -1;
71    }
72    q = (const unsigned char *) data;
73
74    for (i = 0; i < size;) {
75	c = q[i++];
76	c *= 256;
77	if (i < size)
78	    c += q[i];
79	i++;
80	c *= 256;
81	if (i < size)
82	    c += q[i];
83	i++;
84	p[0] = base64_chars[(c & 0x00fc0000) >> 18];
85	p[1] = base64_chars[(c & 0x0003f000) >> 12];
86	p[2] = base64_chars[(c & 0x00000fc0) >> 6];
87	p[3] = base64_chars[(c & 0x0000003f) >> 0];
88	if (i > size)
89	    p[3] = '=';
90	if (i > size + 1)
91	    p[2] = '=';
92	p += 4;
93    }
94    *p = 0;
95    *str = s;
96    return (int) strlen(s);
97}
98
99#define DECODE_ERROR 0xffffffff
100
101static unsigned int
102token_decode(const char *token)
103{
104    int i;
105    unsigned int val = 0;
106    int marker = 0;
107    if (strlen(token) < 4)
108	return DECODE_ERROR;
109    for (i = 0; i < 4; i++) {
110	val *= 64;
111	if (token[i] == '=')
112	    marker++;
113	else if (marker > 0)
114	    return DECODE_ERROR;
115	else
116	    val += pos(token[i]);
117    }
118    if (marker > 2)
119	return DECODE_ERROR;
120    return (marker << 24) | val;
121}
122
123ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
124base64_decode(const char *str, void *data)
125{
126    const char *p;
127    unsigned char *q;
128
129    q = data;
130    for (p = str; *p && (*p == '=' || strchr(base64_chars, *p)); p += 4) {
131	unsigned int val = token_decode(p);
132	unsigned int marker = (val >> 24) & 0xff;
133	if (val == DECODE_ERROR)
134	    return -1;
135	*q++ = (val >> 16) & 0xff;
136	if (marker < 2)
137	    *q++ = (val >> 8) & 0xff;
138	if (marker < 1)
139	    *q++ = val & 0xff;
140    }
141    return q - (unsigned char *) data;
142}
143