comparison lib-src/mmencode.c @ 428:3ecd8885ac67 r21-2-22

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