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