Line data Source code
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 <errno.h>
37 : #include <stdlib.h>
38 : #include <string.h>
39 : #include <limits.h>
40 : #ifdef TEST
41 : #include <stdio.h>
42 : #include <getarg.h>
43 : #include <err.h>
44 : #endif
45 : #include "base64.h"
46 : #include "roken.h"
47 :
48 : #define base64_chars "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
49 :
50 : static int
51 1392487 : pos(char c)
52 : {
53 : #if 'A' == '\301'
54 : const char *p;
55 : for (p = base64_chars; *p; p++)
56 : if (*p == c)
57 : return p - base64_chars;
58 : return -1;
59 : #else
60 1294479 : if (c >= 'A' && c <= 'Z')
61 641683 : return c - 'A';
62 738476 : if (c >= 'a' && c <= 'z')
63 506547 : return ('Z' + 1 - 'A') + c - 'a';
64 223285 : if (c >= '0' && c <= '9')
65 14112 : return ('Z' + 1 - 'A') +
66 189633 : ('z' + 1 - 'a') + c - '0';
67 30648 : if (c == '+')
68 14296 : return 62;
69 14876 : if (c == '/')
70 14588 : return 63;
71 0 : return -1;
72 : #endif
73 : }
74 :
75 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
76 0 : rk_base64_encode(const void *data, int size, char **str)
77 : {
78 0 : char *s, *p;
79 0 : int i;
80 0 : int c;
81 0 : const unsigned char *q;
82 :
83 0 : if (size > INT_MAX/4 || size < 0) {
84 0 : *str = NULL;
85 0 : errno = ERANGE;
86 0 : return -1;
87 : }
88 :
89 0 : p = s = (char *) malloc(size * 4 / 3 + 4);
90 0 : if (p == NULL) {
91 0 : *str = NULL;
92 0 : return -1;
93 : }
94 0 : q = (const unsigned char *) data;
95 :
96 0 : for (i = 0; i < size;) {
97 0 : c = q[i++];
98 0 : c *= 256;
99 0 : if (i < size)
100 0 : c += q[i];
101 0 : i++;
102 0 : c *= 256;
103 0 : if (i < size)
104 0 : c += q[i];
105 0 : i++;
106 0 : p[0] = base64_chars[(c & 0x00fc0000) >> 18];
107 0 : p[1] = base64_chars[(c & 0x0003f000) >> 12];
108 0 : p[2] = base64_chars[(c & 0x00000fc0) >> 6];
109 0 : p[3] = base64_chars[(c & 0x0000003f) >> 0];
110 0 : if (i > size)
111 0 : p[3] = '=';
112 0 : if (i > size + 1)
113 0 : p[2] = '=';
114 0 : p += 4;
115 : }
116 0 : *p = 0;
117 0 : *str = s;
118 0 : return (int) strlen(s);
119 : }
120 :
121 : #define DECODE_ERROR 0xffffffff
122 :
123 : static unsigned int
124 278552 : token_decode(const char *token)
125 : {
126 24508 : int i;
127 278552 : unsigned int val = 0;
128 278552 : int marker = 0;
129 1392760 : for (i = 0; i < 4 && token[i] != '\0'; i++) {
130 1114208 : val *= 64;
131 1114208 : if (token[i] == '=')
132 273 : marker++;
133 1113935 : else if (marker > 0)
134 0 : return DECODE_ERROR;
135 : else
136 1211943 : val += pos(token[i]);
137 : }
138 278552 : if (i < 4 || marker > 2)
139 0 : return DECODE_ERROR;
140 278552 : return (marker << 24) | val;
141 : }
142 :
143 : ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
144 17521 : rk_base64_decode(const char *str, void *data)
145 : {
146 1544 : const char *p;
147 1544 : unsigned char *q;
148 :
149 17521 : q = data;
150 296073 : for (p = str; *p && (*p == '=' || pos(*p) != -1); p += 4) {
151 278552 : unsigned int val = token_decode(p);
152 278552 : unsigned int marker = (val >> 24) & 0xff;
153 278552 : if (val == DECODE_ERROR) {
154 0 : errno = EINVAL;
155 0 : return -1;
156 : }
157 278552 : *q++ = (val >> 16) & 0xff;
158 278552 : if (marker < 2)
159 278469 : *q++ = (val >> 8) & 0xff;
160 278552 : if (marker < 1)
161 278362 : *q++ = val & 0xff;
162 : }
163 17521 : if (q - (unsigned char *) data > INT_MAX) {
164 0 : errno = EOVERFLOW;
165 0 : return -1;
166 : }
167 17521 : return q - (unsigned char *) data;
168 : }
169 :
170 : #ifdef TEST
171 : static int decode_flag;
172 : static int help_flag;
173 :
174 : /*
175 : * The short options are compatible with a subset of the FreeBSD contrib
176 : * vis(1). Heimdal additions have long option names only.
177 : */
178 : static struct getargs args[] = {
179 : { "decode", 'd', arg_flag, &decode_flag, "Decode", NULL },
180 : { "help", 'h', arg_flag, &help_flag, "Print help message", NULL },
181 : };
182 : static size_t num_args = sizeof(args)/sizeof(args[0]);
183 :
184 : int
185 : main(int argc, char **argv)
186 : {
187 : unsigned char *buf = NULL;
188 : size_t buflen = 0;
189 : size_t bufsz = 0;
190 : int goptind = 0;
191 : int ret;
192 :
193 : setprogname("rkbase64");
194 : if (getarg(args, num_args, argc, argv, &goptind) || help_flag) {
195 : arg_printusage(args, num_args, NULL, "FILE | -");
196 : return help_flag ? 0 : 1;
197 : }
198 :
199 : argc -= goptind;
200 : argv += goptind;
201 :
202 : if (help_flag)
203 : return arg_printusage(args, num_args, NULL, "FILE | -- -"), 0;
204 : if (argc != 1)
205 : return arg_printusage(args, num_args, NULL, "FILE | -- -"), 1;
206 :
207 : if (strcmp(argv[0], "-") == 0) {
208 : unsigned char *tmp;
209 : unsigned char d[4096];
210 : size_t bytes;
211 :
212 : while (!feof(stdin) && !ferror(stdin)) {
213 : bytes = fread(d, 1, sizeof(d), stdin);
214 : if (bytes == 0)
215 : continue;
216 : if (buflen + bytes > bufsz) {
217 : if ((tmp = realloc(buf, bufsz + (bufsz >> 2) + sizeof(d))) == NULL)
218 : err(1, "Could not read stdin");
219 : buf = tmp;
220 : bufsz = bufsz + (bufsz >> 2) + sizeof(d);
221 : }
222 : memcpy(buf + buflen, d, bytes);
223 : buflen += bytes;
224 : }
225 : if (ferror(stdin))
226 : err(1, "Could not read stdin");
227 : } else {
228 : void *d;
229 : if ((errno = rk_undumpdata(argv[0], &d, &bufsz)))
230 : err(1, "Could not read %s", argv[0]);
231 : buflen = bufsz;
232 : buf = d;
233 : }
234 :
235 : if (decode_flag) {
236 : unsigned char *d;
237 :
238 : if (buflen == bufsz) {
239 : unsigned char *tmp;
240 :
241 : if ((tmp = realloc(buf, bufsz + 1)) == NULL)
242 : err(1, "Could not decode data");
243 : buf = tmp;
244 : bufsz++;
245 : }
246 : buf[buflen] = '\0';
247 :
248 : if ((d = malloc(buflen * 3 / 4 + 4)) == NULL)
249 : err(1, "Could not decode data");
250 :
251 : if ((ret = rk_base64_decode((const char *)buf, d)) < 0)
252 : err(1, "Could not decode data");
253 : if (fwrite(d, ret, 1, stdout) != 1)
254 : err(1, "Could not write decoded data");
255 : free(d);
256 : } else if (buf) { /* buf can be NULL if we read from an empty file */
257 : char *e;
258 :
259 : if ((ret = rk_base64_encode(buf, buflen, &e)) < 0)
260 : err(1, "Could not encode data");
261 : if (fwrite(e, ret, 1, stdout) != 1)
262 : err(1, "Could not write decoded data");
263 : free(e);
264 : if (fwrite("\n", 1, 1, stdout) != 1)
265 : err(1, "Could not write decoded data");
266 : }
267 : free(buf);
268 : return 0;
269 : }
270 : #endif
|