4 * Encode or decode file as MIME base64 (RFC 1341)
5 * Public domain by John Walker, August 11 1997
6 * Modified slightly for the Citadel system, June 1999
19 #define LINELEN 72 /* Encoded line length (max 76) */
21 typedef unsigned char byte
; /* Byte type */
23 FILE *fi
; /* Input file */
24 FILE *fo
; /* Output file */
25 static byte iobuf
[256]; /* I/O buffer */
26 static int iolen
= 0; /* Bytes left in I/O buffer */
27 static int iocp
= 256; /* Character removal pointer */
28 static int ateof
= FALSE
; /* EOF encountered */
29 static byte dtable
[256]; /* Encode / decode table */
30 static int linelength
= 0; /* Length of encoded output line */
31 static char eol
[] = "\r\n"; /* End of line sequence */
32 static int errcheck
= TRUE
; /* Check decode input for errors ? */
34 /* INBUF -- Fill input buffer with data */
36 static int inbuf(void)
43 l
= fread(iobuf
, 1, sizeof iobuf
, fi
); /* Read input buffer */
56 /* INCHAR -- Return next character from input */
58 static int inchar(void)
69 /* OCHAR -- Output an encoded character, inserting line breaks
72 static void ochar(int c
)
74 if (linelength
>= LINELEN
) {
75 if (fputs(eol
, fo
) == EOF
) {
80 if (putc(((byte
) c
), fo
) == EOF
) {
86 /* ENCODE -- Encode binary file into base64. */
88 static void encode(void)
90 int i
, hiteof
= FALSE
;
92 /* Fill dtable with character encodings. */
94 for (i
= 0; i
< 26; i
++) {
96 dtable
[26 + i
] = 'a' + i
;
98 for (i
= 0; i
< 10; i
++) {
99 dtable
[52 + i
] = '0' + i
;
105 byte igroup
[3], ogroup
[4];
108 igroup
[0] = igroup
[1] = igroup
[2] = 0;
109 for (n
= 0; n
< 3; n
++) {
115 igroup
[n
] = (byte
) c
;
118 ogroup
[0] = dtable
[igroup
[0] >> 2];
119 ogroup
[1] = dtable
[((igroup
[0] & 3) << 4) | (igroup
[1] >> 4)];
120 ogroup
[2] = dtable
[((igroup
[1] & 0xF) << 2) | (igroup
[2] >> 6)];
121 ogroup
[3] = dtable
[igroup
[2] & 0x3F];
123 /* Replace characters in output stream with "=" pad
124 characters if fewer than three characters were
125 read from the end of the input stream. */
133 for (i
= 0; i
< 4; i
++) {
138 if (fputs(eol
, fo
) == EOF
) {
143 /* INSIG -- Return next significant input */
145 static int insig(void)
149 /*CONSTANTCONDITION*/
152 if (c
== EOF
|| (c
> ' ')) {
159 /* DECODE -- Decode base64. */
161 static void decode(void)
165 for (i
= 0; i
< 255; i
++) {
168 for (i
= 'A'; i
<= 'Z'; i
++) {
169 dtable
[i
] = 0 + (i
- 'A');
171 for (i
= 'a'; i
<= 'z'; i
++) {
172 dtable
[i
] = 26 + (i
- 'a');
174 for (i
= '0'; i
<= '9'; i
++) {
175 dtable
[i
] = 52 + (i
- '0');
181 /*CONSTANTCONDITION*/
183 byte a
[4], b
[4], o
[3];
185 for (i
= 0; i
< 4; i
++) {
189 if (errcheck
&& (i
> 0)) {
190 fprintf(stderr
, "Input file incomplete.\n");
195 if (dtable
[c
] & 0x80) {
197 fprintf(stderr
, "Illegal character '%c' in input file.\n", c
);
200 /* Ignoring errors: discard invalid character. */
205 b
[i
] = (byte
) dtable
[c
];
207 o
[0] = (b
[0] << 2) | (b
[1] >> 4);
208 o
[1] = (b
[1] << 4) | (b
[2] >> 2);
209 o
[2] = (b
[2] << 6) | b
[3];
210 i
= a
[2] == '=' ? 1 : (a
[3] == '=' ? 2 : 3);
211 if (fwrite(o
, i
, 1, fo
) == EOF
) {
220 /* USAGE -- Print how-to-call information. */
222 static void usage(char *pname
)
224 fprintf(stderr
, "%s -- Encode/decode file as base64. Call:\n", pname
);
226 " %s [-e[ncode] / -d[ecode]] [-n] [infile] [outfile]\n", pname
);
227 fprintf(stderr
, "\n");
228 fprintf(stderr
, "Options:\n");
229 fprintf(stderr
, " -D Decode base64 encoded file\n");
230 fprintf(stderr
, " -E Encode file into base64\n");
231 fprintf(stderr
, " -N Ignore errors when decoding\n");
232 fprintf(stderr
, " -U Print this message\n");
233 fprintf(stderr
, "\n");
234 fprintf(stderr
, "by John Walker\n");
235 fprintf(stderr
, " WWW: http://www.fourmilab.ch/\n");
240 int main(int argc
, char *argv
[])
242 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");