home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #30 / NN_1992_30.iso / spool / comp / mail / mime / 18 < prev    next >
Encoding:
Text File  |  1992-12-13  |  7.4 KB  |  260 lines

  1. Path: sparky!uunet!ukma!asuvax!chnews!sedona!bhoughto
  2. From: bhoughto@sedona.intel.com (Blair P. Houghton)
  3. Newsgroups: comp.mail.mime
  4. Subject: Re: X.400 and multimedia mail
  5. Date: 13 Dec 1992 19:27:15 GMT
  6. Organization: Intel Corp., Chandler, Arizona
  7. Lines: 248
  8. Message-ID: <1gg2qjINN2df@chnews.intel.com>
  9. References: <1galsqINNr88@gap.caltech.edu> <Bz6H65.EnH@zoo.toronto.edu> <1gfg5uINN5ej@calvin.NYU.EDU>
  10. NNTP-Posting-Host: alfalfa.intel.com
  11.  
  12. In article <1gfg5uINN5ej@calvin.NYU.EDU> roy@mchip00.med.nyu.edu (Roy Smith) writes:
  13. >henry@zoo.toronto.edu (Henry Spencer) writes:
  14. >> And uuencode is essentially identical to base64 except that it's not as
  15. >> good, due to some fundamental design mistakes; in particular, it isn't any
  16. >> more compact.
  17. >
  18. >    What ever happened to btoa?  It came out a bunch of years ago, but
  19. >never seemed to catch on.  As I remember, it was touted as a replacement for
  20. >uuencode with the advantage that it only incurred a 5/4ths expansion instead
  21. >of 4/3rds.  Was there some reason why MIME didn't use btoa?
  22.  
  23. Portability of the character representation.
  24.  
  25. RFC 1341 explicitly cites a desire to use only characters
  26. which appear in all[*] extant literal standards.  The set
  27. [A-Za-z0-9+/] (the brackets aren't included) appears just
  28. about everywhere.  You could probably add [-,.=] to
  29. that[**], but you don't need more than 64 for a 6-bit
  30. code.
  31.  
  32. By the way, in case anyone wants it, I've enclosed some
  33. simple base64 stuff below, as an example of the ascii
  34. implementation on a machine with 8-bit bytes.  It doesn't
  35. ignore newlines in the ascii, yet, but it doesn't create
  36. them, either.
  37.  
  38.                 --Blair
  39.                   "Boy, are we gonna get mail..."
  40.                   -D. Letterman
  41.  
  42.  
  43. [*] almost all? I don't remember any exceptions.
  44. [**] '=', of course, _is_ included, as the padding character.
  45.  
  46.  
  47. --
  48. /* base64.c -- routines to convert to and from base64 encoding */
  49. /* (C) 1992 Blair P. Houghton; All Rights Reserved */
  50.  
  51. #include <stdio.h>
  52. #include <stddef.h>
  53. #include <errno.h>
  54.  
  55. char base64_to_ascii[] = {
  56.     'A',  'B',  'C',  'D',  'E',  'F',  'G',  'H',      /* 00-07 */
  57.     'I',  'J',  'K',  'L',  'M',  'N',  'O',  'P',      /* 08-0f */
  58.     'Q',  'R',  'S',  'T',  'U',  'V',  'W',  'X',      /* 10-17 */
  59.     'Y',  'Z',  'a',  'b',  'c',  'd',  'e',  'f',      /* 18-1f */
  60.     'g',  'h',  'i',  'j',  'k',  'l',  'm',  'n',      /* 20-27 */
  61.     'o',  'p',  'q',  'r',  's',  't',  'u',  'v',      /* 28-2f */
  62.     'w',  'x',  'y',  'z',  '0',  '1',  '2',  '3',      /* 30-37 */
  63.     '4',  '5',  '6',  '7',  '8',  '9',  '+',  '/'       /* 38-3f */
  64. };
  65.  
  66. #define PAD '='
  67.  
  68.  
  69. char ascii_to_base64[] = {
  70.       0,    0,    0,    0,    0,    0,    0,    0,
  71.       0,    0,    0,    0,    0,    0,    0,    0,
  72.       0,    0,    0,    0,    0,    0,    0,    0,
  73.       0,    0,    0,    0,    0,    0,    0,    0,
  74.       0,    0,    0,    0,    0,    0,    0,    0,
  75.       0,    0,    0,   62,    0,    0,    0,   63,
  76.      52,   53,   54,   55,   56,   57,   58,   59,
  77.      60,   61,    0,    0,    0,/**/0,    0,    0,      /* comment at '=' */
  78.       0,    0,    1,    2,    3,    4,    5,    6,
  79.       7,    8,    9,   10,   11,   12,   13,   14,
  80.      15,   16,   17,   18,   19,   20,   21,   22,
  81.      23,   24,   25,    0,    0,    0,    0,    0,
  82.       0,   26,   27,   28,   29,   30,   31,   32,
  83.      33,   34,   35,   36,   37,   38,   39,   40,
  84.      41,   42,   43,   44,   45,   46,   47,   48,
  85.      49,   50,   51,    0,    0,    0,    0,    0
  86. };
  87.  
  88.  
  89. static char s1, s2, s3, s4;
  90.  
  91. void binary_to_ascii_base64( char *s, const char *t )
  92. {
  93.    /*
  94.     *  using `*t++' here instead of the array notation
  95.     *  is an invitation to undefined-order-of-evaluation bugs
  96.     */
  97.     s1 = (t[0] & 0xfc)>>2;
  98.     s2 = (t[0] & 0x03)<<4 | (t[1]&0xf0)>>4;
  99.     s3 = (t[1] & 0x0f)<<2 | (t[2]&0xc0)>>6;
  100.     s4 =  t[2] & 0x3f;
  101.  
  102.     *s++ = (char)base64_to_ascii[ s1 ];
  103.     *s++ = (char)base64_to_ascii[ s2 ];
  104.     *s++ = (char)base64_to_ascii[ s3 ];
  105.     *s = (char)base64_to_ascii[ s4 ];
  106. }
  107.  
  108. void ascii_base64_to_binary( const char *s, char *t )
  109. {
  110.     s1 = ascii_to_base64[ *s++ ];
  111.     s2 = ascii_to_base64[ *s++ ];
  112.     s3 = ascii_to_base64[ *s++ ];
  113.     s4 = ascii_to_base64[ *s ];
  114.  
  115.     *t++ = s1<<2 | (s2&0x30)>>4;
  116.     *t++ = (s2&0x0f)<<4 | (s3&0x3c)>>2;
  117.     *t = (s3&0x03)<<6 | s4;
  118. }
  119.  
  120.  
  121. char *convert_to_binary( const char *s, size_t n_s, size_t *n_t )
  122. {
  123.     static char sx[4], tx[4], *t, *t_start;
  124.     static unsigned spares, n_loop, n;
  125.  
  126.     spares = (s[n_s - 1] == PAD) + (s[n_s - 2] == PAD); /* adding logicals */
  127.  
  128.     n_loop = (spares ? (n_s - 4) : n_s) / 4;            /* # of whole groups */
  129.  
  130.     *n_t = 3 * n_loop + (spares ? (3 - spares) : 0);
  131.  
  132.     if ( *n_t == 0 )
  133.         return NULL;
  134.  
  135.     errno = 0;
  136.     t = t_start = (char *) malloc( *n_t );
  137.     if ( !t ) {
  138.         perror( "convert_to_binary(): allocating binary array" );
  139.         exit( 1 );
  140.     }
  141.  
  142.     while ( n_loop-- ) {
  143.         ascii_base64_to_binary(s,t);
  144.         s += 4;
  145.         t += 3;
  146.     }
  147.  
  148.     /* last quartet */
  149.     if ( spares ) {
  150.         /* one or two PAD characters were found */
  151.         sx[0] = sx[1] = sx[2] = sx[3] = 0;
  152.         tx[0] = tx[1] = tx[2] = 0;
  153.         for( n = 0; n < spares; n++ )
  154.             sx[n] = s[n];
  155.         ascii_base64_to_binary(sx,tx);
  156.         *t = tx[0];                     /* ...X; two PAD chars --> one bin */
  157.         if ( spares == 1 )
  158.             *++t = tx[1];               /* ...XX; one PAD --> two extra bins */
  159.     }
  160.  
  161.     return t_start;
  162. }
  163.  
  164.  
  165. char *convert_to_ascii_base_64( const char *t, size_t n_t, size_t *n_s )
  166. {
  167.     static char tx[4], *s, *s_start;
  168.     static unsigned spares, n_loop, n;
  169.  
  170.     switch( n_t % 3 ) {
  171.         case 1:
  172.             spares = 2;
  173.             break;
  174.         case 2:
  175.             spares = 1;
  176.             break;
  177.         case 0:
  178.             spares = 0;
  179.             break;
  180.     }
  181.  
  182.     n_loop = (spares ? (n_t - (3-spares)) : n_t) / 3;   /* # of whole groups */
  183.  
  184.     *n_s = 4 * (n_loop + (spares != 0));                /* adding logicals */
  185.  
  186.     if ( *n_s < 4 )
  187.         return NULL;
  188.  
  189.     errno = 0;
  190.     s = s_start = (char *) malloc( *n_s );
  191.     if ( !s ) {
  192.         perror( "convert_to_ascii_base_64(): allocating ascii array" );
  193.         exit( 1 );
  194.     }
  195.  
  196.     while ( n_loop-- ) {
  197.         binary_to_ascii_base64(s,t);
  198.         s += 4;
  199.         t += 3;
  200.     }
  201.  
  202.     if ( spares ) {
  203.         /* one or two PAD characters are needed */
  204.         tx[0] = tx[1] = tx[2] = 0;
  205.         for( n = 0; n < spares; n++ )
  206.             tx[n] = t[n];
  207.         binary_to_ascii_base64(s,tx);
  208.         s[3] = PAD;                     /* "....XXX=" */
  209.         if ( spares == 2 )
  210.             s[2] = PAD;                 /* "....XX==" */
  211.     }
  212.  
  213.     return s_start;
  214. }
  215.  
  216. #ifdef BASE64MAIN
  217.  
  218. #include "/eng/eng21/bhoughto/include/slurp.h"
  219.  
  220. int main( void )
  221. {
  222.     char u[4] = { 'a', 'r', '8', 'N' };
  223.     char t[] = { 0xfa, 0xeb, 0xdc, 0xcd };
  224.     char *s, *r;
  225.     size_t n_u, n_t, n_s, n_r, i;
  226.  
  227.     n_u = 4;
  228.     for ( i = 0; i < n_u; i++ )
  229.         printf( "%c ", base64_to_ascii[ ascii_to_base64[ u[i] ] ] );
  230.     printf( "(%d bytes)\n", n_u );
  231.  
  232.     n_t = sizeof(t);
  233.     printf( "%x %x %x %x (%d bytes)\n", t[0], t[1], t[2], t[3], n_t );
  234.  
  235.     s = convert_to_ascii_base_64( t, n_t, &n_s );
  236.  
  237.     for ( i = 0; i < n_s; i++ )
  238.         printf( "%x ", ascii_to_base64[ s[i] ] );
  239.     printf( "\n\"%s\" (%d chars)\n", s, n_s );
  240.  
  241.     r = convert_to_binary( s, n_s, &n_r );
  242.  
  243.     for ( i = 0; i < n_r; i++ )
  244.         printf( "%x ", r[i] );
  245.     printf( "(%d bytes)\n", n_r );
  246.  
  247.     s = slurp( "/tmp/foo" );
  248.  
  249.     n_s = strlen( s ) + 1;
  250.  
  251.     r = convert_to_ascii_base_64( s, n_s, &n_r );
  252.  
  253.     fputs( r, stdout );
  254.  
  255.     fputs( convert_to_binary( r, n_r, &n_s ) , stdout);
  256. }
  257.  
  258. #endif
  259.  
  260.