3 Encode or decode file as MIME base64 (RFC 1341)
6 http://www.fourmilab.ch/
8 This program is in the public domain.
12 #define REVDATE "11th August 1997"
22 #define LINELEN 72 /* Encoded line length (max 76) */
24 typedef unsigned char byte; /* Byte type */
26 static FILE *fi = stdin; /* Input file */
27 static FILE *fo = stdout; /* Output file */
28 static byte iobuf[256]; /* I/O buffer */
29 static int iolen = 0; /* Bytes left in I/O buffer */
30 static int iocp = 256; /* Character removal pointer */
31 static int ateof = FALSE; /* EOF encountered */
32 static byte dtable[256]; /* Encode / decode table */
33 static int linelength = 0; /* Length of encoded output line */
34 static char eol[] = "\r\n"; /* End of line sequence */
35 static int errcheck = TRUE; /* Check decode input for errors ? */
37 /* INBUF -- Fill input buffer with data */
39 static int inbuf(void)
46 l = fread(iobuf, 1, 256, fi); /* Read input buffer */
59 /* INCHAR -- Return next character from input */
61 static int inchar(void)
72 /* OCHAR -- Output an encoded character, inserting line breaks
75 static void ochar(int c)
77 if (linelength >= LINELEN) {
78 if (fputs(eol, fo) == EOF) {
83 if (putc(((byte) c), fo) == EOF) {
89 /* ENCODE -- Encode binary file into base64. */
91 static void encode(void)
93 int i, hiteof = FALSE;
95 /* Fill dtable with character encodings. */
97 for (i = 0; i < 26; i++) {
99 dtable[26 + i] = 'a' + i;
101 for (i = 0; i < 10; i++) {
102 dtable[52 + i] = '0' + i;
108 byte igroup[3], ogroup[4];
111 igroup[0] = igroup[1] = igroup[2] = 0;
112 for (n = 0; n < 3; n++) {
118 igroup[n] = (byte) c;
121 ogroup[0] = dtable[igroup[0] >> 2];
122 ogroup[1] = dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
123 ogroup[2] = dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
124 ogroup[3] = dtable[igroup[2] & 0x3F];
126 /* Replace characters in output stream with "=" pad
127 characters if fewer than three characters were
128 read from the end of the input stream. */
136 for (i = 0; i < 4; i++) {
141 if (fputs(eol, fo) == EOF) {
146 /* INSIG -- Return next significant input */
148 static int insig(void)
152 /*CONSTANTCONDITION*/
155 if (c == EOF || (c > ' ')) {
162 /* DECODE -- Decode base64. */
164 static void decode(void)
168 for (i = 0; i < 255; i++) {
171 for (i = 'A'; i <= 'Z'; i++) {
172 dtable[i] = 0 + (i - 'A');
174 for (i = 'a'; i <= 'z'; i++) {
175 dtable[i] = 26 + (i - 'a');
177 for (i = '0'; i <= '9'; i++) {
178 dtable[i] = 52 + (i - '0');
184 /*CONSTANTCONDITION*/
186 byte a[4], b[4], o[3];
188 for (i = 0; i < 4; i++) {
192 if (errcheck && (i > 0)) {
193 fprintf(stderr, "Input file incomplete.\n");
198 if (dtable[c] & 0x80) {
200 fprintf(stderr, "Illegal character '%c' in input file.\n", c);
203 /* Ignoring errors: discard invalid character. */
208 b[i] = (byte) dtable[c];
210 o[0] = (b[0] << 2) | (b[1] >> 4);
211 o[1] = (b[1] << 4) | (b[2] >> 2);
212 o[2] = (b[2] << 6) | b[3];
213 i = a[2] == '=' ? 1 : (a[3] == '=' ? 2 : 3);
214 if (fwrite(o, i, 1, fo) == EOF) {
223 /* USAGE -- Print how-to-call information. */
225 static void usage(char *pname)
227 fprintf(stderr, "%s -- Encode/decode file as base64. Call:\n", pname);
229 " %s [-e[ncode] / -d[ecode]] [-n] [infile] [outfile]\n", pname);
230 fprintf(stderr, "\n");
231 fprintf(stderr, "Options:\n");
232 fprintf(stderr, " -D Decode base64 encoded file\n");
233 fprintf(stderr, " -E Encode file into base64\n");
234 fprintf(stderr, " -N Ignore errors when decoding\n");
235 fprintf(stderr, " -U Print this message\n");
236 fprintf(stderr, "\n");
237 fprintf(stderr, "by John Walker\n");
238 fprintf(stderr, " WWW: http://www.fourmilab.ch/\n");
243 int main(int argc, char *argv[])
245 int i, f = 0, decoding = FALSE;
248 for (i = 1; i < argc; i++) {
257 case 'D': /* -D Decode */
261 case 'E': /* -E Encode */
265 case 'N': /* -N Suppress error checking */
269 case 'U': /* -U Print how-to-call information */
277 /** Warning! On systems which distinguish text mode and
278 binary I/O (MS-DOS, Macintosh, etc.) the modes in these
279 open statements will have to be made conditional based
280 upon whether an encode or decode is being done, which
281 will have to be specified earlier. But it's worse: if
282 input or output is from standard input or output, the
283 mode will have to be changed on the fly, which is
284 generally system and compiler dependent. 'Twasn't me
285 who couldn't conform to Unix CR/LF convention, so
286 don't ask me to write the code to work around
287 Apple and Microsoft's incompatible standards. **/
290 if (strcmp(cp, "-") != 0) {
291 if ((fi = fopen(cp, "r")) == NULL) {
292 fprintf(stderr, "Cannot open input file %s\n", cp);
300 if (strcmp(cp, "-") != 0) {
301 if ((fo = fopen(cp, "w")) == NULL) {
302 fprintf(stderr, "Cannot open output file %s\n", cp);
310 fprintf(stderr, "Too many file names specified.\n");