52d8a1292d38bbb6747eaa5821434cd878cde2b3
[sgt/utils] / base64 / base64.c
1 #include <stdio.h>
2 #include <errno.h>
3 #include <string.h>
4 #include <stdlib.h>
5
6 #define isbase64(c) ( ((c) >= 'A' && (c) <= 'Z') || \
7 ((c) >= 'a' && (c) <= 'z') || \
8 ((c) >= '0' && (c) <= '9') || \
9 (c) == '+' || (c) == '/' || (c) == '=' \
10 )
11
12 int base64_decode_atom(char *atom, unsigned char *out) {
13 int vals[4];
14 int i, v, len;
15 unsigned word;
16 char c;
17
18 for (i = 0; i < 4; i++) {
19 c = atom[i];
20 if (c >= 'A' && c <= 'Z')
21 v = c - 'A';
22 else if (c >= 'a' && c <= 'z')
23 v = c - 'a' + 26;
24 else if (c >= '0' && c <= '9')
25 v = c - '0' + 52;
26 else if (c == '+')
27 v = 62;
28 else if (c == '/')
29 v = 63;
30 else if (c == '=')
31 v = -1;
32 else
33 return 0; /* invalid atom */
34 vals[i] = v;
35 }
36
37 if (vals[0] == -1 || vals[1] == -1)
38 return 0;
39 if (vals[2] == -1 && vals[3] != -1)
40 return 0;
41
42 if (vals[3] != -1)
43 len = 3;
44 else if (vals[2] != -1)
45 len = 2;
46 else
47 len = 1;
48
49 word = ((vals[0] << 18) |
50 (vals[1] << 12) |
51 ((vals[2] & 0x3F) << 6) |
52 (vals[3] & 0x3F));
53 out[0] = (word >> 16) & 0xFF;
54 if (len > 1)
55 out[1] = (word >> 8) & 0xFF;
56 if (len > 2)
57 out[2] = word & 0xFF;
58 return len;
59 }
60
61 void base64_encode_atom(unsigned char *data, int n, char *out) {
62 static const char base64_chars[] =
63 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
64
65 unsigned word;
66
67 word = data[0] << 16;
68 if (n > 1)
69 word |= data[1] << 8;
70 if (n > 2)
71 word |= data[2];
72 out[0] = base64_chars[(word >> 18) & 0x3F];
73 out[1] = base64_chars[(word >> 12) & 0x3F];
74 if (n > 1)
75 out[2] = base64_chars[(word >> 6) & 0x3F];
76 else
77 out[2] = '=';
78 if (n > 2)
79 out[3] = base64_chars[word & 0x3F];
80 else
81 out[3] = '=';
82 }
83
84 const char usagemsg[] =
85 "usage: base64 [-d] [filename] decode from a file or from stdin\n"
86 " or: base64 -e [-cNNN] [filename] encode from a file or from stdin\n"
87 "where: -d decode mode (default)\n"
88 " -e encode mode\n"
89 " -cNNN set number of chars per line for encoded output\n"
90 " also: base64 --version report version number\n"
91 " base64 --help display this help text\n"
92 " base64 --licence display the (MIT) licence text\n"
93 ;
94
95 void usage(void) {
96 fputs(usagemsg, stdout);
97 }
98
99 const char licencemsg[] =
100 "base64 is copyright 2001,2004 Simon Tatham.\n"
101 "\n"
102 "Permission is hereby granted, free of charge, to any person\n"
103 "obtaining a copy of this software and associated documentation files\n"
104 "(the \"Software\"), to deal in the Software without restriction,\n"
105 "including without limitation the rights to use, copy, modify, merge,\n"
106 "publish, distribute, sublicense, and/or sell copies of the Software,\n"
107 "and to permit persons to whom the Software is furnished to do so,\n"
108 "subject to the following conditions:\n"
109 "\n"
110 "The above copyright notice and this permission notice shall be\n"
111 "included in all copies or substantial portions of the Software.\n"
112 "\n"
113 "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n"
114 "EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n"
115 "MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n"
116 "NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\n"
117 "BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n"
118 "ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n"
119 "CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n"
120 "SOFTWARE.\n"
121 ;
122
123 void licence(void) {
124 fputs(licencemsg, stdout);
125 }
126
127 void version(void) {
128 #define SVN_REV "$Revision$"
129 char rev[sizeof(SVN_REV)];
130 char *p, *q;
131
132 strcpy(rev, SVN_REV);
133
134 for (p = rev; *p && *p != ':'; p++);
135 if (*p) {
136 p++;
137 while (*p && isspace(*p)) p++;
138 for (q = p; *q && *q != '$'; q++);
139 if (*q) *q = '\0';
140 printf("base64 revision %s\n", p);
141 } else {
142 printf("base64: unknown version\n");
143 }
144 }
145
146 int main(int ac, char **av) {
147 int encoding = 0;
148 int cpl = 64;
149 FILE *fp;
150 char *fname;
151 char *eptr;
152
153 fname = NULL;
154
155 while (--ac) {
156 char *v, *p = *++av;
157 if (*p == '-') {
158 while (*p) {
159 char c = *++p;
160 switch (c) {
161 case '-':
162 p++;
163 if (!strcmp(p, "version")) {
164 version();
165 exit(0);
166 } else if (!strcmp(p, "help")) {
167 usage();
168 exit(0);
169 } else if (!strcmp(p, "licence") ||
170 !strcmp(p, "license")) {
171 licence();
172 exit(0);
173 } else {
174 fprintf(stderr, "base64: unknown long option '--%s'\n",
175 p);
176 exit(1);
177 }
178 break;
179 case 'v':
180 case 'V':
181 version();
182 exit(0);
183 break;
184 case 'h':
185 case 'H':
186 usage();
187 exit(0);
188 break;
189 case 'd':
190 encoding = 0;
191 break;
192 case 'e':
193 encoding = 1;
194 break;
195 case 'c':
196 /*
197 * Options requiring values.
198 */
199 v = p+1;
200 if (!*v && ac > 1) {
201 --ac;
202 v = *++av;
203 }
204 if (!*v) {
205 fprintf(stderr, "base64: option '-%c' expects"
206 " an argument\n", c);
207 exit(1);
208 }
209 switch (c) {
210 case 'c':
211 cpl = strtol(v, &eptr, 10);
212 if (eptr && *eptr) {
213 fprintf(stderr, "base64: option -c expects"
214 " a numeric argument\n");
215 exit(1);
216 }
217 if (cpl % 4) {
218 fprintf(stderr, "base64: chars per line should be"
219 " divisible by 4\n");
220 exit(1);
221 }
222 break;
223 }
224 p = "";
225 break;
226 }
227 }
228 } else {
229 if (!fname)
230 fname = p;
231 else {
232 fprintf(stderr, "base64: expected only one filename\n");
233 exit(0);
234 }
235 }
236 }
237
238 if (fname) {
239 fp = fopen(fname, encoding ? "rb" : "r");
240 if (!fp) {
241 fprintf(stderr, "base64: unable to open '%s': %s\n", fname,
242 strerror(errno));
243 exit(1);
244 }
245 } else
246 fp = stdin;
247
248 if (encoding) {
249 unsigned char in[3];
250 char out[4];
251 int column;
252 int n;
253
254 column = 0;
255 while (1) {
256 if (cpl && column >= cpl) {
257 putchar('\n');
258 column = 0;
259 }
260 n = fread(in, 1, 3, fp);
261 if (n == 0) break;
262 base64_encode_atom(in, n, out);
263 fwrite(out, 1, 4, stdout);
264 column += 4;
265 }
266
267 putchar('\n');
268 } else {
269 char in[4];
270 unsigned char out[3];
271 int c, i, n, eof;
272
273 eof = 0;
274 do {
275 for (i = 0; i < 4; i++) {
276 do {
277 c = fgetc(fp);
278 } while (c != EOF && !isbase64(c));
279 if (c == EOF) {
280 eof = 1;
281 break;
282 }
283 in[i] = c;
284 }
285 if (i > 0) {
286 if (i < 4) {
287 fprintf(stderr, "base64: warning: number of base64"
288 " characters was not a multiple of 4\n");
289 while (i < 4) in[i++] = '=';
290 }
291 n = base64_decode_atom(in, out);
292 fwrite(out, 1, n, stdout);
293 }
294 } while (!eof);
295 }
296
297 if (fname)
298 fclose(fp);
299
300 return 0;
301 }