comparison lib-src/mmencode.c @ 14:9ee227acff29 r19-15b90

Import from CVS: tag r19-15b90
author cvs
date Mon, 13 Aug 2007 08:48:42 +0200
parents
children 131b0175ea99
comparison
equal deleted inserted replaced
13:13c6d0aaafe5 14:9ee227acff29
1 /*
2 Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
3
4 Permission to use, copy, modify, and distribute this material
5 for any purpose and without fee is hereby granted, provided
6 that the above copyright notice and this permission notice
7 appear in all copies, and that the name of Bellcore not be
8 used in advertising or publicity pertaining to this
9 material without the specific, prior written permission
10 of an authorized representative of Bellcore. BELLCORE
11 MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY
12 OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS",
13 WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
14 */
15
16 #define NEWLINE_CHAR '\n'
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <ctype.h>
20 #include <string.h>
21
22 static void
23 output64chunk(int c1, int c2, int c3, int pads, FILE *outfile);
24
25 static char basis_64[] =
26 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
27
28 static char index_64[128] = {
29 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
30 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
31 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
32 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
33 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
34 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
35 -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
36 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
37 };
38
39 #define char64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])
40
41 /*
42 char64(c)
43 char c;
44 {
45 char *s = (char *) strchr(basis_64, c);
46 if (s) return(s-basis_64);
47 return(-1);
48 }
49 */
50
51 /* the following gets a character, but fakes it properly into two chars if there's a newline character */
52 static int InNewline=0;
53
54 static int
55 nextcharin(infile, PortableNewlines)
56 FILE *infile;
57 int PortableNewlines;
58 {
59 int c;
60
61 #ifndef NEWLINE_CHAR
62 return(getc(infile));
63 #else
64 if (!PortableNewlines) return(getc(infile));
65 if (InNewline) {
66 InNewline = 0;
67 return(10); /* LF */
68 }
69 c = getc(infile);
70 if (c == NEWLINE_CHAR) {
71 InNewline = 1;
72 return(13); /* CR */
73 }
74 return(c);
75 #endif
76 }
77
78 static void
79 to64(FILE *infile, FILE *outfile, int PortableNewlines)
80 {
81 int c1, c2, c3, ct=0;
82 InNewline = 0; /* always reset it */
83 while ((c1 = nextcharin(infile, PortableNewlines)) != EOF) {
84 c2 = nextcharin(infile, PortableNewlines);
85 if (c2 == EOF) {
86 output64chunk(c1, 0, 0, 2, outfile);
87 } else {
88 c3 = nextcharin(infile, PortableNewlines);
89 if (c3 == EOF) {
90 output64chunk(c1, c2, 0, 1, outfile);
91 } else {
92 output64chunk(c1, c2, c3, 0, outfile);
93 }
94 }
95 ct += 4;
96 if (ct > 71) {
97 putc('\n', outfile);
98 ct = 0;
99 }
100 }
101 if (ct) putc('\n', outfile);
102 fflush(outfile);
103 }
104
105 static void
106 output64chunk(int c1, int c2, int c3, int pads, FILE *outfile)
107 {
108 putc(basis_64[c1>>2], outfile);
109 putc(basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)], outfile);
110 if (pads == 2) {
111 putc('=', outfile);
112 putc('=', outfile);
113 } else if (pads) {
114 putc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
115 putc('=', outfile);
116 } else {
117 putc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
118 putc(basis_64[c3 & 0x3F], outfile);
119 }
120 }
121
122 static int
123 PendingBoundary(char *s, char **Boundaries, int *BoundaryCt)
124 {
125 int i, len;
126
127 if (s[0] != '-' || s[1] != '-') return(0);
128
129
130 for (i=0; i < *BoundaryCt; ++i) {
131 len = strlen(Boundaries[i]);
132 if (!strncmp(s, Boundaries[i], len)) {
133 if (s[len] == '-' && s[len+1] == '-') *BoundaryCt = i;
134 return(1);
135 }
136 }
137 return(0);
138 }
139
140 /* If we're in portable newline mode, we have to convert CRLF to the
141 local newline convention on output */
142
143 static int CRpending = 0;
144
145 #ifdef NEWLINE_CHAR
146 static void
147 almostputc(int c, FILE *outfile, int PortableNewlines)
148 {
149 if (CRpending) {
150 if (c == 10) {
151 putc(NEWLINE_CHAR, outfile);
152 CRpending = 0;
153 } else {
154 putc(13, outfile);
155 if (c != 13) {
156 putc(c, outfile);
157 CRpending = 0;
158 }
159 }
160 } else {
161 if (PortableNewlines && c == 13) {
162 CRpending = 1;
163 } else {
164 putc(c, outfile);
165 }
166 }
167 }
168 #else
169 static void
170 almostputc(int c, FILE *outfile, int PortableNewlines)
171 {
172 putc(c, outfile);
173 }
174 #endif
175
176 static void
177 from64(FILE *infile, FILE *outfile,
178 char **boundaries, int *boundaryct, int PortableNewlines)
179 {
180 int c1, c2, c3, c4;
181 int newline = 1, DataDone = 0;
182
183 /* always reinitialize */
184 CRpending = 0;
185 while ((c1 = getc(infile)) != EOF) {
186 if (isspace(c1)) {
187 if (c1 == '\n') {
188 newline = 1;
189 } else {
190 newline = 0;
191 }
192 continue;
193 }
194 if (newline && boundaries && c1 == '-') {
195 char Buf[200];
196 /* a dash is NOT base 64, so all bets are off if NOT a boundary */
197 ungetc(c1, infile);
198 fgets(Buf, sizeof(Buf), infile);
199 if (boundaries
200 && (Buf[0] == '-')
201 && (Buf[1] == '-')
202 && PendingBoundary(Buf, boundaries, boundaryct)) {
203 return;
204 }
205 fprintf(stderr, "Ignoring unrecognized boundary line: %s\n", Buf);
206 continue;
207 }
208 if (DataDone) continue;
209 newline = 0;
210 do {
211 c2 = getc(infile);
212 } while (c2 != EOF && isspace(c2));
213 do {
214 c3 = getc(infile);
215 } while (c3 != EOF && isspace(c3));
216 do {
217 c4 = getc(infile);
218 } while (c4 != EOF && isspace(c4));
219 if (c2 == EOF || c3 == EOF || c4 == EOF) {
220 fprintf(stderr, "Warning: base64 decoder saw premature EOF!\n");
221 return;
222 }
223 if (c1 == '=' || c2 == '=') {
224 DataDone=1;
225 continue;
226 }
227 c1 = char64(c1);
228 c2 = char64(c2);
229 almostputc(((c1<<2) | ((c2&0x30)>>4)), outfile, PortableNewlines);
230 if (c3 == '=') {
231 DataDone = 1;
232 } else {
233 c3 = char64(c3);
234 almostputc((((c2&0XF) << 4) | ((c3&0x3C) >> 2)), outfile, PortableNewlines);
235 if (c4 == '=') {
236 DataDone = 1;
237 } else {
238 c4 = char64(c4);
239 almostputc((((c3&0x03) <<6) | c4), outfile, PortableNewlines);
240 }
241 }
242 }
243 if (CRpending) putc(13, outfile); /* Don't drop a lone trailing char 13 */
244 }
245
246 static char basis_hex[] = "0123456789ABCDEF";
247 static char index_hex[128] = {
248 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
249 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
250 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
251 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1,
252 -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
253 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
254 -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
255 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
256 };
257
258 /* The following version generated complaints on Solaris. */
259 /* #define hexchar(c) (((c) < 0 || (c) > 127) ? -1 : index_hex[(c)]) */
260 /* Since we're no longer ever calling it with anything signed, this should work: */
261 #define hexchar(c) (((c) > 127) ? -1 : index_hex[(c)])
262
263 /*
264 hexchar(c)
265 char c;
266 {
267 char *s;
268 if (islower(c)) c = toupper(c);
269 s = (char *) strchr(basis_hex, c);
270 if (s) return(s-basis_hex);
271 return(-1);
272 }
273 */
274
275 static void
276 toqp(FILE *infile, FILE *outfile)
277 {
278 int c, ct=0, prevc=255;
279 while ((c = getc(infile)) != EOF) {
280 if ((c < 32 && (c != '\n' && c != '\t'))
281 || (c == '=')
282 || (c >= 127)
283 /* Following line is to avoid single periods alone on lines,
284 which messes up some dumb smtp implementations, sigh... */
285 || (ct == 0 && c == '.')) {
286 putc('=', outfile);
287 putc(basis_hex[c>>4], outfile);
288 putc(basis_hex[c&0xF], outfile);
289 ct += 3;
290 prevc = 'A'; /* close enough */
291 } else if (c == '\n') {
292 if (prevc == ' ' || prevc == '\t') {
293 putc('=', outfile); /* soft & hard lines */
294 putc(c, outfile);
295 }
296 putc(c, outfile);
297 ct = 0;
298 prevc = c;
299 } else {
300 if (c == 'F' && prevc == '\n') {
301 /* HORRIBLE but clever hack suggested by MTR for sendmail-avoidance */
302 c = getc(infile);
303 if (c == 'r') {
304 c = getc(infile);
305 if (c == 'o') {
306 c = getc(infile);
307 if (c == 'm') {
308 c = getc(infile);
309 if (c == ' ') {
310 /* This is the case we are looking for */
311 fputs("=46rom", outfile);
312 ct += 6;
313 } else {
314 fputs("From", outfile);
315 ct += 4;
316 }
317 } else {
318 fputs("Fro", outfile);
319 ct += 3;
320 }
321 } else {
322 fputs("Fr", outfile);
323 ct += 2;
324 }
325 } else {
326 putc('F', outfile);
327 ++ct;
328 }
329 ungetc(c, infile);
330 prevc = 'x'; /* close enough -- printable */
331 } else { /* END horrible hack */
332 putc(c, outfile);
333 ++ct;
334 prevc = c;
335 }
336 }
337 if (ct > 72) {
338 putc('=', outfile);
339 putc('\n', outfile);
340 ct = 0;
341 prevc = '\n';
342 }
343 }
344 if (ct) {
345 putc('=', outfile);
346 putc('\n', outfile);
347 }
348 }
349
350 static void
351 fromqp(FILE *infile, FILE *outfile, char **boundaries, int *boundaryct)
352 {
353 unsigned int c1, c2;
354 int sawnewline = 1, neednewline = 0;
355 /* The neednewline hack is necessary because the newline leading into
356 a multipart boundary is part of the boundary, not the data */
357
358 while ((c1 = getc(infile)) != EOF) {
359 if (sawnewline && boundaries && (c1 == '-')) {
360 char Buf[200];
361 unsigned char *s;
362
363 ungetc(c1, infile);
364 fgets(Buf, sizeof(Buf), infile);
365 if (boundaries
366 && (Buf[0] == '-')
367 && (Buf[1] == '-')
368 && PendingBoundary(Buf, boundaries, boundaryct)) {
369 return;
370 }
371 /* Not a boundary, now we must treat THIS line as q-p, sigh */
372 if (neednewline) {
373 putc('\n', outfile);
374 neednewline = 0;
375 }
376 for (s=(unsigned char *) Buf; *s; ++s) {
377 if (*s == '=') {
378 if (!*++s) break;
379 if (*s == '\n') {
380 /* ignore it */
381 sawnewline = 1;
382 } else {
383 c1 = hexchar(*s);
384 if (!*++s) break;
385 c2 = hexchar(*s);
386 putc(c1<<4 | c2, outfile);
387 }
388 } else {
389 #ifdef MSDOS
390 if (*s == '\n')
391 putc('\r', outfile); /* insert CR for binary-mode write */
392 #endif
393 putc(*s, outfile);
394 }
395 }
396 } else {
397 if (neednewline) {
398 putc('\n', outfile);
399 neednewline = 0;
400 }
401 if (c1 == '=') {
402 sawnewline = 0;
403 c1 = getc(infile);
404 if (c1 == '\n') {
405 /* ignore it */
406 sawnewline = 1;
407 } else {
408 c2 = getc(infile);
409 c1 = hexchar(c1);
410 c2 = hexchar(c2);
411 putc(c1<<4 | c2, outfile);
412 if (c2 == '\n') sawnewline = 1;
413 }
414 } else {
415 if (c1 == '\n') {
416 sawnewline = 1;
417 neednewline = 1;
418 } else {
419 sawnewline = 0;
420 putc(c1, outfile);
421 }
422 }
423 }
424 }
425 if (neednewline) {
426 putc('\n', outfile);
427 neednewline = 0;
428 }
429 }
430
431
432 /*
433 Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
434
435 Permission to use, copy, modify, and distribute this material
436 for any purpose and without fee is hereby granted, provided
437 that the above copyright notice and this permission notice
438 appear in all copies, and that the name of Bellcore not be
439 used in advertising or publicity pertaining to this
440 material without the specific, prior written permission
441 of an authorized representative of Bellcore. BELLCORE
442 MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY
443 OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS",
444 WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
445 */
446 #ifdef MSDOS
447 #include <fcntl.h>
448 #endif
449
450 #define BASE64 1
451 #define QP 2 /* quoted-printable */
452
453 int main(int argc, char *argv[])
454 {
455 int encode = 1, which = BASE64, i, portablenewlines = 0;
456 FILE *fp = stdin;
457 FILE *fpo = stdout;
458
459 for (i=1; i<argc; ++i) {
460 if (argv[i][0] == '-') {
461 switch (argv[i][1]) {
462 case 'o':
463 if (++i >= argc) {
464 fprintf(stderr, "mimencode: -o requires a file name.\n");
465 exit(-1);
466 }
467 fpo = fopen(argv[i], "w");
468 if (!fpo) {
469 perror(argv[i]);
470 exit(-1);
471 }
472 break;
473 case 'u':
474 encode = 0;
475 break;
476 case 'q':
477 which = QP;
478 break;
479 case 'p':
480 portablenewlines = 1;
481 break;
482 case 'b':
483 which = BASE64;
484 break;
485 default:
486 fprintf(stderr,
487 "Usage: mmencode [-u] [-q] [-b] [-p] [-o outputfile] [file name]\n");
488 exit(-1);
489 }
490 } else {
491 #ifdef MSDOS
492 if (encode)
493 fp = fopen(argv[i], "rb");
494 else
495 {
496 fp = fopen(argv[i], "rt");
497 setmode(fileno(fpo), O_BINARY);
498 } /* else */
499 #else
500 fp = fopen(argv[i], "r");
501 #endif /* MSDOS */
502 if (!fp) {
503 perror(argv[i]);
504 exit(-1);
505 }
506 }
507 }
508 #ifdef MSDOS
509 if (fp == stdin) setmode(fileno(fp), O_BINARY);
510 #endif /* MSDOS */
511 if (which == BASE64) {
512 if (encode) {
513 to64(fp, fpo, portablenewlines);
514 } else {
515 from64(fp,fpo, (char **) NULL, (int *) 0, portablenewlines);
516 }
517 } else {
518 if (encode) toqp(fp, fpo); else fromqp(fp, fpo, NULL, 0);
519 }
520 return(0);
521 }
522