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'
24 output64chunk(int c1, int c2, int c3, int pads, FILE *outfile);
26 static signed char basis_64[] =
27 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
29 static signed char index_64[128] = {
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,-1, -1,-1,-1,-1,
32 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
33 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1,
34 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
35 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
36 -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
37 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
40 #define char64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)])
46 char *s = (char *) strchr(basis_64, c);
47 if (s) return(s-basis_64);
52 /* the following gets a character, but fakes it properly into two chars if there's a newline character */
53 static int InNewline=0;
56 nextcharin (FILE *infile, int PortableNewlines)
63 if (!PortableNewlines) return(getc(infile));
69 if (c == NEWLINE_CHAR) {
78 to64(FILE *infile, FILE *outfile, int PortableNewlines)
81 InNewline = 0; /* always reset it */
82 while ((c1 = nextcharin(infile, PortableNewlines)) != EOF) {
83 c2 = nextcharin(infile, PortableNewlines);
85 output64chunk(c1, 0, 0, 2, outfile);
87 c3 = nextcharin(infile, PortableNewlines);
89 output64chunk(c1, c2, 0, 1, outfile);
91 output64chunk(c1, c2, c3, 0, outfile);
100 if (ct) putc('\n', outfile);
105 output64chunk(int c1, int c2, int c3, int pads, FILE *outfile)
107 putc(basis_64[c1>>2], outfile);
108 putc(basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)], outfile);
113 putc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
116 putc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile);
117 putc(basis_64[c3 & 0x3F], outfile);
122 PendingBoundary(char *s, char **Boundaries, int *BoundaryCt)
126 if (s[0] != '-' || s[1] != '-') return(0);
129 for (i=0; i < *BoundaryCt; ++i) {
130 len = strlen(Boundaries[i]);
131 if (!strncmp(s, Boundaries[i], len)) {
132 if (s[len] == '-' && s[len+1] == '-') *BoundaryCt = i;
139 /* If we're in portable newline mode, we have to convert CRLF to the
140 local newline convention on output */
142 static int CRpending = 0;
146 almostputc(int c, FILE *outfile, int PortableNewlines)
150 putc(NEWLINE_CHAR, outfile);
160 if (PortableNewlines && c == 13) {
169 almostputc(int c, FILE *outfile, int PortableNewlines)
176 from64(FILE *infile, FILE *outfile,
177 char **boundaries, int *boundaryct, int PortableNewlines)
180 int newline = 1, DataDone = 0;
182 /* always reinitialize */
184 while ((c1 = getc(infile)) != EOF) {
193 if (newline && boundaries && c1 == '-') {
195 /* a dash is NOT base 64, so all bets are off if NOT a boundary */
197 fgets(Buf, sizeof(Buf), infile);
201 && PendingBoundary(Buf, boundaries, boundaryct)) {
204 fprintf(stderr, "Ignoring unrecognized boundary line: %s\n", Buf);
207 if (DataDone) continue;
211 } while (c2 != EOF && isspace(c2));
214 } while (c3 != EOF && isspace(c3));
217 } while (c4 != EOF && isspace(c4));
218 if (c2 == EOF || c3 == EOF || c4 == EOF) {
219 fprintf(stderr, "Warning: base64 decoder saw premature EOF!\n");
222 if (c1 == '=' || c2 == '=') {
228 almostputc(((c1<<2) | ((c2&0x30)>>4)), outfile, PortableNewlines);
233 almostputc((((c2&0XF) << 4) | ((c3&0x3C) >> 2)), outfile, PortableNewlines);
238 almostputc((((c3&0x03) <<6) | c4), outfile, PortableNewlines);
242 if (CRpending) putc(13, outfile); /* Don't drop a lone trailing char 13 */
245 static signed char basis_hex[] = "0123456789ABCDEF";
246 static signed char index_hex[128] = {
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 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
250 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1,
251 -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
252 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
253 -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1,
254 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1
257 /* The following version generated complaints on Solaris. */
258 /* #define hexchar(c) (((c) < 0 || (c) > 127) ? -1 : index_hex[(c)]) */
259 /* Since we're no longer ever calling it with anything signed, this should work: */
260 #define hexchar(c) (((c) > 127) ? -1 : index_hex[(c)])
267 if (islower(c)) c = toupper(c);
268 s = (char *) strchr(basis_hex, c);
269 if (s) return(s-basis_hex);
275 toqp(FILE *infile, FILE *outfile)
277 int c, ct=0, prevc=255;
278 while ((c = getc(infile)) != EOF) {
279 if ((c < 32 && (c != '\n' && c != '\t'))
282 /* Following line is to avoid single periods alone on lines,
283 which messes up some dumb smtp implementations, sigh... */
284 || (ct == 0 && c == '.')) {
286 putc(basis_hex[c>>4], outfile);
287 putc(basis_hex[c&0xF], outfile);
289 prevc = 'A'; /* close enough */
290 } else if (c == '\n') {
291 if (prevc == ' ' || prevc == '\t') {
292 putc('=', outfile); /* soft & hard lines */
299 if (c == 'F' && prevc == '\n') {
300 /* HORRIBLE but clever hack suggested by MTR for sendmail-avoidance */
309 /* This is the case we are looking for */
310 fputs("=46rom", outfile);
313 fputs("From", outfile);
317 fputs("Fro", outfile);
321 fputs("Fr", outfile);
329 prevc = 'x'; /* close enough -- printable */
330 } else { /* END horrible hack */
350 fromqp(FILE *infile, FILE *outfile, char **boundaries, int *boundaryct)
353 int sawnewline = 1, neednewline = 0;
354 /* The neednewline hack is necessary because the newline leading into
355 a multipart boundary is part of the boundary, not the data */
357 while ((c1 = getc(infile)) != EOF) {
358 if (sawnewline && boundaries && (c1 == '-')) {
363 fgets(Buf, sizeof(Buf), infile);
367 && PendingBoundary(Buf, boundaries, boundaryct)) {
370 /* Not a boundary, now we must treat THIS line as q-p, sigh */
375 for (s=(unsigned char *) Buf; *s; ++s) {
385 putc(c1<<4 | c2, outfile);
390 putc('\r', outfile); /* insert CR for binary-mode write */
410 putc(c1<<4 | c2, outfile);
411 if (c2 == '\n') sawnewline = 1;
432 Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
434 Permission to use, copy, modify, and distribute this material
435 for any purpose and without fee is hereby granted, provided
436 that the above copyright notice and this permission notice
437 appear in all copies, and that the name of Bellcore not be
438 used in advertising or publicity pertaining to this
439 material without the specific, prior written permission
440 of an authorized representative of Bellcore. BELLCORE
441 MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY
442 OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS",
443 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");
501 #endif /* WIN32_NATIVE */
509 if (fp == stdin) setmode(fileno(fp), O_BINARY);
510 #endif /* WIN32_NATIVE */
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);