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 (FILE *infile, int PortableNewlines)
62 if (!PortableNewlines) return(getc(infile));
68 if (c == NEWLINE_CHAR) {
77 to64(FILE *infile, FILE *outfile, int PortableNewlines)
80 InNewline = 0; /* always reset it */
81 while ((c1 = nextcharin(infile, PortableNewlines)) != EOF) {
82 c2 = nextcharin(infile, PortableNewlines);
84 output64chunk(c1, 0, 0, 2, outfile);
86 c3 = nextcharin(infile, PortableNewlines);
88 output64chunk(c1, c2, 0, 1, outfile);
90 output64chunk(c1, c2, c3, 0, outfile);
99 if (ct) putc('\n', outfile);
104 output64chunk(int c1, int c2, int c3, int pads, FILE *outfile)
106 putc(basis_64[c1>>2], outfile);
107 putc(basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)], outfile);
112 putc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
115 putc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
116 putc(basis_64[c3 & 0x3F], outfile);
121 PendingBoundary(char *s, char **Boundaries, int *BoundaryCt)
125 if (s[0] != '-' || s[1] != '-') return(0);
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;
138 /* If we're in portable newline mode, we have to convert CRLF to the
139 local newline convention on output */
141 static int CRpending = 0;
145 almostputc(int c, FILE *outfile, int PortableNewlines)
149 putc(NEWLINE_CHAR, outfile);
159 if (PortableNewlines && c == 13) {
168 almostputc(int c, FILE *outfile, int PortableNewlines)
175 from64(FILE *infile, FILE *outfile,
176 char **boundaries, int *boundaryct, int PortableNewlines)
179 int newline = 1, DataDone = 0;
181 /* always reinitialize */
183 while ((c1 = getc(infile)) != EOF) {
192 if (newline && boundaries && c1 == '-') {
194 /* a dash is NOT base 64, so all bets are off if NOT a boundary */
196 fgets(Buf, sizeof(Buf), infile);
200 && PendingBoundary(Buf, boundaries, boundaryct)) {
203 fprintf(stderr, "Ignoring unrecognized boundary line: %s\n", Buf);
206 if (DataDone) continue;
210 } while (c2 != EOF && isspace(c2));
213 } while (c3 != EOF && isspace(c3));
216 } while (c4 != EOF && isspace(c4));
217 if (c2 == EOF || c3 == EOF || c4 == EOF) {
218 fprintf(stderr, "Warning: base64 decoder saw premature EOF!\n");
221 if (c1 == '=' || c2 == '=') {
227 almostputc(((c1<<2) | ((c2&0x30)>>4)), outfile, PortableNewlines);
232 almostputc((((c2&0XF) << 4) | ((c3&0x3C) >> 2)), outfile, PortableNewlines);
237 almostputc((((c3&0x03) <<6) | c4), outfile, PortableNewlines);
241 if (CRpending) putc(13, outfile); /* Don't drop a lone trailing char 13 */
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
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)])
266 if (islower(c)) c = toupper(c);
267 s = (char *) strchr(basis_hex, c);
268 if (s) return(s-basis_hex);
274 toqp(FILE *infile, FILE *outfile)
276 int c, ct=0, prevc=255;
277 while ((c = getc(infile)) != EOF) {
278 if ((c < 32 && (c != '\n' && c != '\t'))
281 /* Following line is to avoid single periods alone on lines,
282 which messes up some dumb smtp implementations, sigh... */
283 || (ct == 0 && c == '.')) {
285 putc(basis_hex[c>>4], outfile);
286 putc(basis_hex[c&0xF], outfile);
288 prevc = 'A'; /* close enough */
289 } else if (c == '\n') {
290 if (prevc == ' ' || prevc == '\t') {
291 putc('=', outfile); /* soft & hard lines */
298 if (c == 'F' && prevc == '\n') {
299 /* HORRIBLE but clever hack suggested by MTR for sendmail-avoidance */
308 /* This is the case we are looking for */
309 fputs("=46rom", outfile);
312 fputs("From", outfile);
316 fputs("Fro", outfile);
320 fputs("Fr", outfile);
328 prevc = 'x'; /* close enough -- printable */
329 } else { /* END horrible hack */
349 fromqp(FILE *infile, FILE *outfile, char **boundaries, int *boundaryct)
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 */
356 while ((c1 = getc(infile)) != EOF) {
357 if (sawnewline && boundaries && (c1 == '-')) {
362 fgets(Buf, sizeof(Buf), infile);
366 && PendingBoundary(Buf, boundaries, boundaryct)) {
369 /* Not a boundary, now we must treat THIS line as q-p, sigh */
374 for (s=(unsigned char *) Buf; *s; ++s) {
384 putc(c1<<4 | c2, outfile);
389 putc('\r', outfile); /* insert CR for binary-mode write */
409 putc(c1<<4 | c2, outfile);
410 if (c2 == '\n') sawnewline = 1;
431 Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
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.
449 #define QP 2 /* quoted-printable */
451 int main(int argc, char *argv[])
453 int encode = 1, which = BASE64, i, portablenewlines = 0;
457 for (i=1; i<argc; ++i) {
458 if (argv[i][0] == '-') {
459 switch (argv[i][1]) {
462 fprintf(stderr, "mimencode: -o requires a file name.\n");
465 fpo = fopen(argv[i], "w");
478 portablenewlines = 1;
485 "Usage: mmencode [-u] [-q] [-b] [-p] [-o outputfile] [file name]\n");
491 fp = fopen(argv[i], "rb");
494 fp = fopen(argv[i], "rt");
495 setmode(fileno(fpo), O_BINARY);
498 fp = fopen(argv[i], "r");
507 if (fp == stdin) setmode(fileno(fp), O_BINARY);
509 if (which == BASE64) {
511 to64(fp, fpo, portablenewlines);
513 from64(fp,fpo, (char **) NULL, (int *) 0, portablenewlines);
516 if (encode) toqp(fp, fpo); else fromqp(fp, fpo, NULL, 0);