2 Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
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.
16 #define NEWLINE_CHAR '\n'
23 output64chunk(int c1, int c2, int c3, int pads, FILE *outfile);
25 static signed char basis_64[] =
26 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
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
39 #define char64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])
45 char *s = (char *) strchr(basis_64, c);
46 if (s) return(s-basis_64);
51 /* the following gets a character, but fakes it properly into two chars if there's a newline character */
52 static int InNewline=0;
55 nextcharin(infile, PortableNewlines)
64 if (!PortableNewlines) return(getc(infile));
70 if (c == NEWLINE_CHAR) {
79 to64(FILE *infile, FILE *outfile, int PortableNewlines)
82 InNewline = 0; /* always reset it */
83 while ((c1 = nextcharin(infile, PortableNewlines)) != EOF) {
84 c2 = nextcharin(infile, PortableNewlines);
86 output64chunk(c1, 0, 0, 2, outfile);
88 c3 = nextcharin(infile, PortableNewlines);
90 output64chunk(c1, c2, 0, 1, outfile);
92 output64chunk(c1, c2, c3, 0, outfile);
101 if (ct) putc('\n', outfile);
106 output64chunk(int c1, int c2, int c3, int pads, FILE *outfile)
108 putc(basis_64[c1>>2], outfile);
109 putc(basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)], outfile);
114 putc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
117 putc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
118 putc(basis_64[c3 & 0x3F], outfile);
123 PendingBoundary(char *s, char **Boundaries, int *BoundaryCt)
127 if (s[0] != '-' || s[1] != '-') return(0);
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;
140 /* If we're in portable newline mode, we have to convert CRLF to the
141 local newline convention on output */
143 static int CRpending = 0;
147 almostputc(int c, FILE *outfile, int PortableNewlines)
151 putc(NEWLINE_CHAR, outfile);
161 if (PortableNewlines && c == 13) {
170 almostputc(int c, FILE *outfile, int PortableNewlines)
177 from64(FILE *infile, FILE *outfile,
178 char **boundaries, int *boundaryct, int PortableNewlines)
181 int newline = 1, DataDone = 0;
183 /* always reinitialize */
185 while ((c1 = getc(infile)) != EOF) {
194 if (newline && boundaries && c1 == '-') {
196 /* a dash is NOT base 64, so all bets are off if NOT a boundary */
198 fgets(Buf, sizeof(Buf), infile);
202 && PendingBoundary(Buf, boundaries, boundaryct)) {
205 fprintf(stderr, "Ignoring unrecognized boundary line: %s\n", Buf);
208 if (DataDone) continue;
212 } while (c2 != EOF && isspace(c2));
215 } while (c3 != EOF && isspace(c3));
218 } while (c4 != EOF && isspace(c4));
219 if (c2 == EOF || c3 == EOF || c4 == EOF) {
220 fprintf(stderr, "Warning: base64 decoder saw premature EOF!\n");
223 if (c1 == '=' || c2 == '=') {
229 almostputc(((c1<<2) | ((c2&0x30)>>4)), outfile, PortableNewlines);
234 almostputc((((c2&0XF) << 4) | ((c3&0x3C) >> 2)), outfile, PortableNewlines);
239 almostputc((((c3&0x03) <<6) | c4), outfile, PortableNewlines);
243 if (CRpending) putc(13, outfile); /* Don't drop a lone trailing char 13 */
246 static signed char basis_hex[] = "0123456789ABCDEF";
247 static signed 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
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)])
268 if (islower(c)) c = toupper(c);
269 s = (char *) strchr(basis_hex, c);
270 if (s) return(s-basis_hex);
276 toqp(FILE *infile, FILE *outfile)
278 int c, ct=0, prevc=255;
279 while ((c = getc(infile)) != EOF) {
280 if ((c < 32 && (c != '\n' && c != '\t'))
283 /* Following line is to avoid single periods alone on lines,
284 which messes up some dumb smtp implementations, sigh... */
285 || (ct == 0 && c == '.')) {
287 putc(basis_hex[c>>4], outfile);
288 putc(basis_hex[c&0xF], outfile);
290 prevc = 'A'; /* close enough */
291 } else if (c == '\n') {
292 if (prevc == ' ' || prevc == '\t') {
293 putc('=', outfile); /* soft & hard lines */
300 if (c == 'F' && prevc == '\n') {
301 /* HORRIBLE but clever hack suggested by MTR for sendmail-avoidance */
310 /* This is the case we are looking for */
311 fputs("=46rom", outfile);
314 fputs("From", outfile);
318 fputs("Fro", outfile);
322 fputs("Fr", outfile);
330 prevc = 'x'; /* close enough -- printable */
331 } else { /* END horrible hack */
351 fromqp(FILE *infile, FILE *outfile, char **boundaries, int *boundaryct)
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 */
358 while ((c1 = getc(infile)) != EOF) {
359 if (sawnewline && boundaries && (c1 == '-')) {
364 fgets(Buf, sizeof(Buf), infile);
368 && PendingBoundary(Buf, boundaries, boundaryct)) {
371 /* Not a boundary, now we must treat THIS line as q-p, sigh */
376 for (s=(unsigned char *) Buf; *s; ++s) {
386 putc(c1<<4 | c2, outfile);
391 putc('\r', outfile); /* insert CR for binary-mode write */
411 putc(c1<<4 | c2, outfile);
412 if (c2 == '\n') sawnewline = 1;
433 Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
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.
451 #define QP 2 /* quoted-printable */
453 int main(int argc, char *argv[])
455 int encode = 1, which = BASE64, i, portablenewlines = 0;
459 for (i=1; i<argc; ++i) {
460 if (argv[i][0] == '-') {
461 switch (argv[i][1]) {
464 fprintf(stderr, "mimencode: -o requires a file name.\n");
467 fpo = fopen(argv[i], "w");
480 portablenewlines = 1;
487 "Usage: mmencode [-u] [-q] [-b] [-p] [-o outputfile] [file name]\n");
493 fp = fopen(argv[i], "rb");
496 fp = fopen(argv[i], "rt");
497 setmode(fileno(fpo), O_BINARY);
500 fp = fopen(argv[i], "r");
509 if (fp == stdin) setmode(fileno(fp), O_BINARY);
511 if (which == BASE64) {
513 to64(fp, fpo, portablenewlines);
515 from64(fp,fpo, (char **) NULL, (int *) 0, portablenewlines);
518 if (encode) toqp(fp, fpo); else fromqp(fp, fpo, NULL, 0);