3 Encode or decode file as MIME base64 (RFC 1341)
6 http://www.fourmilab.ch/
8 This program is in the public domain.
10 Revision date: 11th August 1997
12 Modified slightly for the Citadel/UX system, June 1999
13 http://uncnsrd.mt-kisco.ny.us/citadel
26 #define LINELEN 72 /* Encoded line length (max 76) */
28 typedef unsigned char byte; /* Byte type */
30 FILE *fi; /* Input file */
31 FILE *fo; /* Output file */
32 static byte iobuf[256]; /* I/O buffer */
33 static int iolen = 0; /* Bytes left in I/O buffer */
34 static int iocp = 256; /* Character removal pointer */
35 static int ateof = FALSE; /* EOF encountered */
36 static byte dtable[256]; /* Encode / decode table */
37 static int linelength = 0; /* Length of encoded output line */
38 static char eol[] = "\r\n"; /* End of line sequence */
39 static int errcheck = TRUE; /* Check decode input for errors ? */
41 /* INBUF -- Fill input buffer with data */
43 static int inbuf(void)
50 l = fread(iobuf, 1, 256, fi); /* Read input buffer */
63 /* INCHAR -- Return next character from input */
65 static int inchar(void)
76 /* OCHAR -- Output an encoded character, inserting line breaks
79 static void ochar(int c)
81 if (linelength >= LINELEN) {
82 if (fputs(eol, fo) == EOF) {
87 if (putc(((byte) c), fo) == EOF) {
93 /* ENCODE -- Encode binary file into base64. */
95 static void encode(void)
97 int i, hiteof = FALSE;
99 /* Fill dtable with character encodings. */
101 for (i = 0; i < 26; i++) {
103 dtable[26 + i] = 'a' + i;
105 for (i = 0; i < 10; i++) {
106 dtable[52 + i] = '0' + i;
112 byte igroup[3], ogroup[4];
115 igroup[0] = igroup[1] = igroup[2] = 0;
116 for (n = 0; n < 3; n++) {
122 igroup[n] = (byte) c;
125 ogroup[0] = dtable[igroup[0] >> 2];
126 ogroup[1] = dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
127 ogroup[2] = dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
128 ogroup[3] = dtable[igroup[2] & 0x3F];
130 /* Replace characters in output stream with "=" pad
131 characters if fewer than three characters were
132 read from the end of the input stream. */
140 for (i = 0; i < 4; i++) {
145 if (fputs(eol, fo) == EOF) {
150 /* INSIG -- Return next significant input */
152 static int insig(void)
156 /*CONSTANTCONDITION*/
159 if (c == EOF || (c > ' ')) {
166 /* DECODE -- Decode base64. */
168 static void decode(void)
172 for (i = 0; i < 255; i++) {
175 for (i = 'A'; i <= 'Z'; i++) {
176 dtable[i] = 0 + (i - 'A');
178 for (i = 'a'; i <= 'z'; i++) {
179 dtable[i] = 26 + (i - 'a');
181 for (i = '0'; i <= '9'; i++) {
182 dtable[i] = 52 + (i - '0');
188 /*CONSTANTCONDITION*/
190 byte a[4], b[4], o[3];
192 for (i = 0; i < 4; i++) {
196 if (errcheck && (i > 0)) {
197 fprintf(stderr, "Input file incomplete.\n");
202 if (dtable[c] & 0x80) {
204 fprintf(stderr, "Illegal character '%c' in input file.\n", c);
207 /* Ignoring errors: discard invalid character. */
212 b[i] = (byte) dtable[c];
214 o[0] = (b[0] << 2) | (b[1] >> 4);
215 o[1] = (b[1] << 4) | (b[2] >> 2);
216 o[2] = (b[2] << 6) | b[3];
217 i = a[2] == '=' ? 1 : (a[3] == '=' ? 2 : 3);
218 if (fwrite(o, i, 1, fo) == EOF) {
227 /* USAGE -- Print how-to-call information. */
229 static void usage(char *pname)
231 fprintf(stderr, "%s -- Encode/decode file as base64. Call:\n", pname);
233 " %s [-e[ncode] / -d[ecode]] [-n] [infile] [outfile]\n", pname);
234 fprintf(stderr, "\n");
235 fprintf(stderr, "Options:\n");
236 fprintf(stderr, " -D Decode base64 encoded file\n");
237 fprintf(stderr, " -E Encode file into base64\n");
238 fprintf(stderr, " -N Ignore errors when decoding\n");
239 fprintf(stderr, " -U Print this message\n");
240 fprintf(stderr, "\n");
241 fprintf(stderr, "by John Walker\n");
242 fprintf(stderr, " WWW: http://www.fourmilab.ch/\n");
247 int main(int argc, char *argv[])
249 int i, f = 0, decoding = FALSE;
255 for (i = 1; i < argc; i++) {
264 case 'D': /* -D Decode */
268 case 'E': /* -E Encode */
272 case 'N': /* -N Suppress error checking */
276 case 'U': /* -U Print how-to-call information */
284 /** Warning! On systems which distinguish text mode and
285 binary I/O (MS-DOS, Macintosh, etc.) the modes in these
286 open statements will have to be made conditional based
287 upon whether an encode or decode is being done, which
288 will have to be specified earlier. But it's worse: if
289 input or output is from standard input or output, the
290 mode will have to be changed on the fly, which is
291 generally system and compiler dependent. 'Twasn't me
292 who couldn't conform to Unix CR/LF convention, so
293 don't ask me to write the code to work around
294 Apple and Microsoft's incompatible standards. **/
297 if (strcmp(cp, "-") != 0) {
298 if ((fi = fopen(cp, "r")) == NULL) {
299 fprintf(stderr, "Cannot open input file %s\n", cp);
307 if (strcmp(cp, "-") != 0) {
308 if ((fo = fopen(cp, "w")) == NULL) {
309 fprintf(stderr, "Cannot open output file %s\n", cp);
317 fprintf(stderr, "Too many file names specified.\n");