2 /* MIME base64 encoder/decoder by Karl Hahn hahn@lds.loral.com 3-Aug-94 */
3 /* modified 30-Sep-94 by Karl Hahn hahn@lds.loral.com: handle multiple
5 /* modified 12-Jan-95 by Karl Hahn hahn@lds.loral.com: handle file names
6 that are encased in quotes */
7 /* modified 18-Jan-95 by Karl Hahn hahn@lds.loral.com: prevent complete
8 failure if filename in name field matches name of input file */
9 /* modified 19-Jan-95 by Karl Hahn hahn@lds.loral.com: prevent early exit
10 if last decoded character falls on a multiple of 3 -- would cause error
11 message and failure to rename output file if rename was necessary */
12 /* modified 19-Jan-95 by Karl Hahn hahn@lds.loral.com: prevent complete
13 failure if a line of text preceding the MIME64 stuff contains no
14 non-base64 characters */
15 /* modified 19-Jan-95 by Karl Hahn hahn@lds.loral.com: fixed command
16 line parser to prevent missing a name field preceded by another
18 /* modified 19-Jan-95 by Karl Hahn hahn@lds.loral.com: prevent error
19 message at the end of decoding each section. Terminates output
20 file now on a blank line as well as the conditions that did so
28 #define strcmpi(x,y) strcasecmp(x,y)
31 char alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
34 enum TOKENTYPE { NONE, BLANKS, PUNCT, TAG, NAME, CONTENT };
43 int compare_token( struct TOKEN *token, char *text )
48 char blivit1, blivit2;
50 count = token->length;
61 while ( (count > 0) && ( result != 0 ) )
63 blivit1 = token->text[index++];
64 if ( (blivit1 >= 'a' ) && (blivit1 <= 'z') )
70 if ( (blivit2 >= 'a' ) && (blivit2 <= 'z') )
75 if ( blivit1 != blivit2 )
86 int ispunct( char blivit )
88 if ( ( blivit >= 'a' ) && (blivit <= 'z' ) )
93 if ( ( ( blivit < '0' ) ||
94 ( ( blivit > '9' ) && (blivit < 'A') ) ||
96 ( blivit != '-') && (blivit != '/') && (blivit != '.') )
106 void fixname( char *name )
108 while ( *name != '\0' )
111 if (ispunct( *name ) )
120 void acquire_token( char *line, enum TOKENTYPE type, struct TOKEN *token )
122 int doneflag=0, startflag=1;
124 enum TOKENTYPE nextstate=NONE;
127 if (token->type == NONE)
133 index = token->index + token->length;
137 while ( doneflag == 0 )
139 blivit = line[index];
140 if ( (blivit >= 'a') && (blivit <= 'z') )
165 else if ( ispunct( blivit ) )
168 token->index = index;
172 token->type = nextstate;
173 token->index = index;
182 token->index = index;
183 token->text = line + index;
186 else if ( blivit == ' ' )
188 token->type = BLANKS;
189 token->index = index;
190 if ( line[ token->index ] == ';' )
194 else if ( line[ token->index ] == '=' )
200 else if ( ispunct( blivit ) )
206 if ( line[ token->index ] == ';' )
210 else if ( line[ token->index ] == '=' )
215 token->type = nextstate;
216 token->index = index;
221 if ( ispunct( blivit ) )
223 token->length = index - token->index;
224 token->text = line + token->index;
227 if ( ( ( type == TAG ) || ( type == NONE ) ) && !startflag)
231 else if (blivit == ' ')
233 token->type = BLANKS;
234 token->index = index;
239 token->index = index;
249 if ( ispunct( blivit ) )
251 token->length = index - token->index;
252 token->text = line + token->index;
263 if ( ( ( type == NAME ) || ( type == NONE ) ) && !startflag )
267 else if (blivit == ' ')
269 token->type = BLANKS;
270 token->index = index;
275 token->index = index;
285 if ( ispunct( blivit ) )
287 token->length = index - token->index;
288 token->text = line + token->index;
291 if ( ( ( type == CONTENT ) || ( type == NONE ) ) && !startflag )
295 else if (blivit == ' ')
297 token->type = BLANKS;
298 token->index = index;
303 token->index = index;
316 void fputch( char blivit, FILE *f )
318 /* if (blivit == '\n') fputc( '\r', f );*/
322 int classify_args( int narg,
323 char *rawargs[], char *fileargs[], char *optargs[] )
325 int index, jndex, kndex;
328 for ( index = 0, jndex = 0, kndex = 0; index < narg; index++ )
330 argptr = rawargs[index];
334 optargs[kndex++] = argptr;
338 fileargs[jndex++] = argptr;
345 int cvt_ascii( unsigned char alpha )
347 if ( (alpha >= 'A') && (alpha <= 'Z') ) return (int)(alpha - 'A');
348 else if ( (alpha >= 'a') && (alpha <= 'z') )
349 return 26 + (int)(alpha - 'a');
350 else if ( (alpha >= '0') && (alpha <= '9' ) )
351 return 52 + (int)(alpha - '0');
352 else if ( alpha == '+' ) return 62;
353 else if ( alpha == '/' ) return 63;
354 else if ( alpha == '=' ) return -2;
358 char *fileargs[64], *optargs[64];
361 unsigned long int accum;
366 int main( int nargs, char *cargs[] )
368 int n_options, n_files, index, jndex, shift, save_shift;
369 enum { ENCODE, DECODE } whattodo = DECODE;
370 int help_flag = 0, replace_flag = 0, perm_replace_flag = 0, quit = 0;
372 FILE *fin, *fout = NULL, *dummy;
373 unsigned char blivit;
374 unsigned long accum, value;
375 char buf[80], dumname[80];
384 n_options = classify_args( nargs, cargs, fileargs, optargs );
386 n_files = nargs - n_options;
388 if ( n_files < 2 ) help_flag = 1;
390 for ( index = 0; index < n_options; index++ )
392 if ( ( optargs[index][0] == 'e' ) ||
393 ( optargs[index][0] == 'E' ) ) whattodo = ENCODE;
394 if ( optargs[index][0] == '?' ) help_flag = 1;
399 printf( "mime64 infile [outfile] [-option] [-option] etc.\n\n"
400 "convert between binary and MIME BASE64 format\n\n"
401 " -e MIME base64 encode (default is decode)\n"
402 " -? display help message\n\n"
403 "if no outfile given, output file replaces infile\n" );
406 if ( n_files < 2 ) exit(0);
408 if ( whattodo == DECODE )
410 fin = fopen( fileargs[1], "r" );
414 fin = fopen( fileargs[1], "rb" );
419 printf( "%s file not found\n", fileargs[1] );
425 if ( whattodo == DECODE )
427 sprintf( dumname, "%s", fileargs[2] );
431 fout = fopen( fileargs[2], "w" );
435 printf( "Couldn't open %s for output\n", fileargs[2] );
441 if ( whattodo == DECODE )
443 sprintf( dumname, "%s", fileargs[1] );
447 fout = fopen( "$$$$$$$$.$$$", "w" );
458 if ( whattodo == DECODE )
464 while ( ( !feof( fin ) ) && (quit == 0) )
466 fgets( buf, 80, fin );
469 if ( ( dumname[0] != '\0' ) && ( shift != 0 ) )
471 printf( "Unexpected end of file encountered in %s\n"
472 "last few bytes may have been lost\n", dumname );
477 else if ( cycle_flag == 0 )
488 if ( (decode_state == 1) &&
489 ( (buf[0] == '\n') || (buf[0] < '+') ) )
495 printf( "Unexpected end of section in %s\n"
496 "last few bytes may have been lost\n", dumname );
504 if ( decode_state == 0 )
507 (buf[index] != '\n') && (buf[index] != '\0') &&
511 if ( ( (buf[index] >= 'A') && (buf[index] <= 'Z') ) ||
512 ( (buf[index] >= 'a') && (buf[index] <= 'z') ) ||
513 ( (buf[index] >= '0') && (buf[index] <= '9') ) ||
514 (buf[index] == '+') ||
515 (buf[index] == '/') ||
516 (buf[index] == '=') )
526 if ( decode_state <= 0 )
532 acquire_token( buf, TAG, &token );
533 if ( compare_token( &token, "Content-Type") )
537 acquire_token( buf, NAME, &token );
538 if ( compare_token( &token, "name" ) )
540 acquire_token( buf, CONTENT, &token );
542 if ( ( replace_flag ) ||
545 sscanf( token.text, "%s", dumname );
548 if ( strcmpi( dumname, fileargs[1] ) != 0 )
554 if ( perm_replace_flag )
557 "More than one output file named %s\n",
565 } while ( token.type != NONE );
567 else if ( compare_token( &token, "Content-transfer-encoding" ) )
573 acquire_token( buf, NAME, &token );
574 if ( compare_token( &token, "base64" ) )
578 } while ( token.type != NONE );
582 else if ( skipflag != 0 )
592 printf( "Section %s not MIME base64\n", dumname );
596 printf( "Creating %s\n", dumname );
597 if ( strcmpi( dumname, fileargs[1] ) == 0 )
604 fout = fopen( "$$$$$$$$.$$$", "wb" );
608 fout = fopen( dumname, "wb" );
613 printf( "Couldn't open %s for output\n", dumname );
622 printf( "No filename given for subsequent section\n" );
636 for ( index = 0; (buf[index] != '\n') && (buf[index] != '\0'); index++)
638 value = cvt_ascii( buf[index] );
648 value = accum >> shift;
649 blivit = (unsigned char)value & 0xFFl;
650 fputc( blivit, fout );
664 "Content-Type: text/plain; charset=US-ASCII; name=%s\n"
665 "Content-transfer-encoding: base64\n\n", fileargs[1] );
670 while ( ( !feof( fin ) ) || (shift != 0) )
672 if ( ( !feof( fin ) ) && ( quit == 0 ) )
674 blivit = fgetc( fin );
690 if ( (quit == 0) || (shift != 0) )
692 value = (unsigned long)blivit;
701 value = (accum >> shift) & 0x3Fl;
702 blivit = alphabet[value];
704 buf[index++] = blivit;
708 fprintf( fout, "%s\n", buf );
719 if ( save_shift == 2 )
725 fprintf( fout, "%s\n", buf );
733 fprintf( fout, "%s\n", buf );
737 else if ( save_shift == 4 )
743 fprintf( fout, "%s\n", buf );
751 fprintf( fout, "%s\n", buf );
763 perm_replace_flag = 1;
765 if ( ( whattodo == DECODE ) && ( decode_state <= 0 ) && ( outcount == 0 ) )
767 remove( "$$$$$$$$.$$$" );
768 printf( "No MIME base64 lines found in %s\n", fileargs[1] );
773 if ( ( whattodo == DECODE ) && ( decode_state <= 0 ) && ( outcount == 0 ) )
775 remove( fileargs[2] );
776 printf( "No MIME base64 lines found in %s\n", fileargs[1] );
785 } while ( !feof( fin ) );
788 if ( perm_replace_flag )
790 remove( fileargs[1] );
791 rename( "$$$$$$$$.$$$", fileargs[1] );