"Fossies" - the Fresh Open Source Software Archive

Member "xstress/src/b64.c" (19 Feb 2009, 17413 Bytes) of package /linux/privat/old/xstress-src-0.375-beta-20090219.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "b64.c" see the Fossies "Dox" file reference documentation.

    1 /*********************************************************************\
    2 
    3 MODULE NAME:    b64.c
    4 
    5 AUTHOR:         Bob Trower 08/04/01
    6 
    7 PROJECT:        Crypt Data Packaging
    8 
    9 COPYRIGHT:      Copyright (c) Trantor Standard Systems Inc., 2001
   10 
   11 NOTE:           This source code may be used as you wish, subject to
   12                 the MIT license.  See the LICENCE section below.
   13 
   14 DESCRIPTION:
   15                 This little utility implements the Base64
   16                 Content-Transfer-Encoding standard described in
   17                 RFC1113 (http://www.faqs.org/rfcs/rfc1113.html).
   18 
   19                 This is the coding scheme used by MIME to allow
   20                 binary data to be transferred by SMTP mail.
   21 
   22                 Groups of 3 bytes from a binary stream are coded as
   23                 groups of 4 bytes in a text stream.
   24 
   25                 The input stream is 'padded' with zeros to create
   26                 an input that is an even multiple of 3.
   27 
   28                 A special character ('=') is used to denote padding so
   29                 that the stream can be decoded back to its exact size.
   30 
   31                 Encoded output is formatted in lines which should
   32                 be a maximum of 72 characters to conform to the
   33                 specification.  This program defaults to 72 characters,
   34                 but will allow more or less through the use of a
   35                 switch.  The program enforces a minimum line size
   36                 of 4 characters.
   37 
   38                 Example encoding:
   39 
   40                 The stream 'ABCD' is 32 bits long.  It is mapped as
   41                 follows:
   42 
   43                 ABCD
   44 
   45                  A (65)     B (66)     C (67)     D (68)   (None) (None)
   46                 01000001   01000010   01000011   01000100
   47 
   48                 16 (Q)  20 (U)  9 (J)   3 (D)    17 (R) 0 (A)  NA (=) NA (=)
   49                 010000  010100  001001  000011   010001 000000 000000 000000
   50 
   51 
   52                 QUJDRA==
   53 
   54                 Decoding is the process in reverse.  A 'decode' lookup
   55                 table has been created to avoid string scans.
   56 
   57 DESIGN GOALS:   Specifically:
   58         Code is a stand-alone utility to perform base64 
   59         encoding/decoding. It should be genuinely useful 
   60         when the need arises and it meets a need that is 
   61         likely to occur for some users.  
   62         Code acts as sample code to show the author's 
   63         design and coding style.  
   64 
   65         Generally: 
   66         This program is designed to survive:
   67         Everything you need is in a single source file.
   68         It compiles cleanly using a vanilla ANSI C compiler.
   69         It does its job correctly with a minimum of fuss.  
   70         The code is not overly clever, not overly simplistic 
   71         and not overly verbose. 
   72         Access is 'cut and paste' from a web page.  
   73         Terms of use are reasonable.  
   74 
   75 VALIDATION:     Non-trivial code is never without errors.  This
   76                 file likely has some problems, since it has only
   77                 been tested by the author.  It is expected with most
   78                 source code that there is a period of 'burn-in' when
   79                 problems are identified and corrected.  That being
   80                 said, it is possible to have 'reasonably correct'
   81                 code by following a regime of unit test that covers
   82                 the most likely cases and regression testing prior
   83                 to release.  This has been done with this code and
   84                 it has a good probability of performing as expected.
   85 
   86                 Unit Test Cases:
   87 
   88                 case 0:empty file:
   89                     CASE0.DAT  ->  ->
   90                     (Zero length target file created
   91                     on both encode and decode.)
   92 
   93                 case 1:One input character:
   94                     CASE1.DAT A -> QQ== -> A
   95 
   96                 case 2:Two input characters:
   97                     CASE2.DAT AB -> QUJD -> AB
   98 
   99                 case 3:Three input characters:
  100                     CASE3.DAT ABC -> QUJD -> ABC
  101 
  102                 case 4:Four input characters:
  103                     case4.dat ABCD -> QUJDRA== -> ABCD
  104 
  105                 case 5:All chars from 0 to ff, linesize set to 50:
  106 
  107                     AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIj
  108                     JCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZH
  109                     SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWpr
  110                     bG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6P
  111                     kJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKz
  112                     tLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX
  113                     2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7
  114                     /P3+/w==
  115 
  116                 case 6:Mime Block from e-mail:
  117                     (Data same as test case 5)
  118 
  119                 case 7: Large files:
  120                     Tested 28 MB file in/out.
  121 
  122                 case 8: Random Binary Integrity:
  123                     This binary program (b64.exe) was encoded to base64,
  124                     back to binary and then executed.
  125 
  126                 case 9 Stress:
  127                     All files in a working directory encoded/decoded
  128                     and compared with file comparison utility to
  129                     ensure that multiple runs do not cause problems
  130                     such as exhausting file handles, tmp storage, etc.
  131 
  132                 -------------
  133 
  134                 Syntax, operation and failure:
  135                     All options/switches tested.  Performs as
  136                     expected.
  137 
  138                 case 10:
  139                     No Args -- Shows Usage Screen
  140                     Return Code 1 (Invalid Syntax)
  141                 case 11:
  142                     One Arg (invalid) -- Shows Usage Screen
  143                     Return Code 1 (Invalid Syntax)
  144                 case 12:
  145                     One Arg Help (-?) -- Shows detailed Usage Screen.
  146                     Return Code 0 (Success -- help request is valid).
  147                 case 13:
  148                     One Arg Help (-h) -- Shows detailed Usage Screen.
  149                     Return Code 0 (Success -- help request is valid).
  150                 case 14:
  151                     One Arg (valid) -- Uses stdin/stdout (filter)
  152                     Return Code 0 (Sucess)
  153                 case 15:
  154                     Two Args (invalid file) -- shows system error.
  155                     Return Code 2 (File Error)
  156                 case 16:
  157                     Encode non-existent file -- shows system error.
  158                     Return Code 2 (File Error)
  159                 case 17:
  160                     Out of disk space -- shows system error.
  161                     Return Code 3 (File I/O Error)
  162 
  163                 -------------
  164 
  165                 Compile/Regression test:
  166                     gcc compiled binary under Cygwin
  167                     Microsoft Visual Studio under Windows 2000
  168                     Microsoft Version 6.0 C under Windows 2000
  169 
  170 DEPENDENCIES:   None
  171 
  172 LICENCE:        Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc.
  173 
  174                 Permission is hereby granted, free of charge, to any person
  175                 obtaining a copy of this software and associated
  176                 documentation files (the "Software"), to deal in the
  177                 Software without restriction, including without limitation
  178                 the rights to use, copy, modify, merge, publish, distribute,
  179                 sublicense, and/or sell copies of the Software, and to
  180                 permit persons to whom the Software is furnished to do so,
  181                 subject to the following conditions:
  182 
  183                 The above copyright notice and this permission notice shall
  184                 be included in all copies or substantial portions of the
  185                 Software.
  186 
  187                 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
  188                 KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  189                 WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  190                 PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
  191                 OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  192                 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  193                 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  194                 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  195 
  196 VERSION HISTORY:
  197                 Bob Trower 08/04/01 -- Create Version 0.00.00B
  198 
  199 \******************************************************************* */
  200 
  201 #include <stdio.h>
  202 #include <stdlib.h>
  203 
  204 /*
  205 ** Translation Table as described in RFC1113
  206 */
  207 static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  208 
  209 /*
  210 ** Translation Table to decode (created by author)
  211 */
  212 static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
  213 
  214 /*
  215 ** encodeblock
  216 **
  217 ** encode 3 8-bit binary bytes as 4 '6-bit' characters
  218 */
  219 void encodeblock( unsigned char in[3], unsigned char out[4], int len )
  220 {
  221     out[0] = cb64[ in[0] >> 2 ];
  222     out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
  223     out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
  224     out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
  225 }
  226 
  227 /*
  228 ** encode
  229 **
  230 ** base64 encode a stream adding padding and line breaks as per spec.
  231 */
  232 void encode( FILE *infile, FILE *outfile, int linesize )
  233 {
  234     unsigned char in[3], out[4];
  235     int i, len, blocksout = 0;
  236 
  237     while( !feof( infile ) ) {
  238         len = 0;
  239         for( i = 0; i < 3; i++ ) {
  240             in[i] = (unsigned char) getc( infile );
  241             if( !feof( infile ) ) {
  242                 len++;
  243             }
  244             else {
  245                 in[i] = 0;
  246             }
  247         }
  248         if( len ) {
  249             encodeblock( in, out, len );
  250             for( i = 0; i < 4; i++ ) {
  251                 putc( out[i], outfile );
  252             }
  253             blocksout++;
  254         }
  255         if( blocksout >= (linesize/4) || feof( infile ) ) {
  256             if( blocksout ) {
  257                 fprintf( outfile, "\r\n" );
  258             }
  259             blocksout = 0;
  260         }
  261     }
  262 }
  263 
  264 /*
  265 ** decodeblock
  266 **
  267 ** decode 4 '6-bit' characters into 3 8-bit binary bytes
  268 */
  269 void decodeblock( unsigned char in[4], unsigned char out[3] )
  270 {   
  271     out[ 0 ] = (unsigned char ) (in[0] << 2 | in[1] >> 4);
  272     out[ 1 ] = (unsigned char ) (in[1] << 4 | in[2] >> 2);
  273     out[ 2 ] = (unsigned char ) (((in[2] << 6) & 0xc0) | in[3]);
  274 }
  275 
  276 /*
  277 ** decode
  278 **
  279 ** decode a base64 encoded stream discarding padding, line breaks and noise
  280 */
  281 void decode( FILE *infile, FILE *outfile )
  282 {
  283     unsigned char in[4], out[3], v;
  284     int i, len;
  285 
  286     while( !feof( infile ) ) {
  287         for( len = 0, i = 0; i < 4 && !feof( infile ); i++ ) {
  288             v = 0;
  289             while( !feof( infile ) && v == 0 ) {
  290                 v = (unsigned char) getc( infile );
  291                 v = (unsigned char) ((v < 43 || v > 122) ? 0 : cd64[ v - 43 ]);
  292                 if( v ) {
  293                     v = (unsigned char) ((v == '$') ? 0 : v - 61);
  294                 }
  295             }
  296             if( !feof( infile ) ) {
  297                 len++;
  298                 if( v ) {
  299                     in[ i ] = (unsigned char) (v - 1);
  300                 }
  301             }
  302             else {
  303                 in[i] = 0;
  304             }
  305         }
  306         if( len ) {
  307             decodeblock( in, out );
  308             for( i = 0; i < len - 1; i++ ) {
  309                 putc( out[i], outfile );
  310             }
  311         }
  312     }
  313 }
  314 
  315 /*
  316 ** returnable errors
  317 **
  318 ** Error codes returned to the operating system.
  319 **
  320 */
  321 #define B64_SYNTAX_ERROR        1
  322 #define B64_FILE_ERROR          2
  323 #define B64_FILE_IO_ERROR       3
  324 #define B64_ERROR_OUT_CLOSE     4
  325 #define B64_LINE_SIZE_TO_MIN    5
  326 
  327 /*
  328 ** b64_message
  329 **
  330 ** Gather text messages in one place.
  331 **
  332 */
  333 char *b64_message( int errcode )
  334 {
  335     #define B64_MAX_MESSAGES 6
  336     char *msgs[ B64_MAX_MESSAGES ] = {
  337             "b64:000:Invalid Message Code.",
  338             "b64:001:Syntax Error -- check help for usage.",
  339             "b64:002:File Error Opening/Creating Files.",
  340             "b64:003:File I/O Error -- Note: output file not removed.",
  341             "b64:004:Error on output file close.",
  342             "b64:004:linesize set to minimum."
  343     };
  344     char *msg = msgs[ 0 ];
  345 
  346     if( errcode > 0 && errcode < B64_MAX_MESSAGES ) {
  347         msg = msgs[ errcode ];
  348     }
  349 
  350     return( msg );
  351 }
  352 
  353 /*
  354 ** b64
  355 **
  356 ** 'engine' that opens streams and calls encode/decode
  357 */
  358 
  359 int b64( int opt, char *infilename, char *outfilename, int linesize )
  360 {
  361     FILE *infile;
  362     int retcode = B64_FILE_ERROR;
  363 
  364     if( !infilename ) {
  365         infile = stdin;
  366     }
  367     else {
  368         infile = fopen( infilename, "rb" );
  369     }
  370     if( !infile ) {
  371         perror( infilename );
  372     }
  373     else {
  374         FILE *outfile;
  375         if( !outfilename ) {
  376             outfile = stdout;
  377         }
  378         else {
  379             outfile = fopen( outfilename, "wb" );
  380         }
  381         if( !outfile ) {
  382             perror( outfilename );
  383         }
  384         else {
  385             if( opt == 'e' ) {
  386                 encode( infile, outfile, linesize );
  387             }
  388             else {
  389                 decode( infile, outfile );
  390             }
  391             if (ferror( infile ) || ferror( outfile )) {
  392                 retcode = B64_FILE_IO_ERROR;
  393             }
  394             else {
  395                  retcode = 0;
  396             }
  397             if( outfile != stdout ) {
  398                 if( fclose( outfile ) != 0 ) {
  399                     perror( b64_message( B64_ERROR_OUT_CLOSE ) );
  400                     retcode = B64_FILE_IO_ERROR;
  401                 }
  402             }
  403         }
  404         if( infile != stdin ) {
  405             fclose( infile );
  406         }
  407     }
  408 
  409     return( retcode );
  410 }
  411 
  412 /*
  413 ** showuse
  414 **
  415 ** display usage information, help, version info
  416 */
  417 void showuse( int morehelp )
  418 {
  419     {
  420         printf( "\n" );
  421         printf( "  b64      (Base64 Encode/Decode)      Bob Trower 08/03/01 \n" );
  422         printf( "           (C) Copr Bob Trower 1986-01.      Version 0.00B \n" );
  423         printf( "  Usage:   b64 -option  [ -l num ] [<FileIn> [<FileOut>]]  \n" );
  424         printf( "  Purpose: This program is a simple utility that implements\n" );
  425         printf( "           Base64 Content-Transfer-Encoding (RFC1113).     \n" );
  426     }
  427     if( !morehelp ) {
  428         printf( "           Use -h option for additional help.              \n" );
  429     }
  430     else {
  431         printf( "  Options: -e  encode to Base64   -h  This help text.      \n" );
  432         printf( "           -d  decode from Base64 -?  This help text.      \n" );
  433         printf( "  Note:    -l  use to change line size (from 72 characters)\n" );
  434         printf( "  Returns: 0 = success.  Non-zero is an error code.        \n" );
  435         printf( "  ErrCode: 1 = Bad Syntax, 2 = File Open, 3 = File I/O     \n" );
  436         printf( "  Example: b64 -e binfile b64file     <- Encode to b64     \n" );
  437         printf( "           b64 -d b64file binfile     <- Decode from b64   \n" );
  438         printf( "           b64 -e -l40 infile outfile <- Line Length of 40 \n" );
  439         printf( "  Note:    Will act as a filter, but this should only be   \n" );
  440         printf( "           used on text files due to translations made by  \n" );
  441         printf( "           operating systems.                              \n" );
  442         printf( "  Release: 0.00.00, Tue Aug 7   2:00:00 2001, ANSI-SOURCE C\n" );
  443     }
  444 }
  445 
  446 #define B64_DEF_LINE_SIZE   72
  447 #define B64_MIN_LINE_SIZE    4
  448 
  449 #define THIS_OPT(ac, av) (ac > 1 ? av[1][0] == '-' ? av[1][1] : 0 : 0)
  450 
  451 /*
  452 ** main
  453 **
  454 ** parse and validate arguments and call b64 engine or help
  455 */
  456 int main( int argc, char **argv )
  457 {
  458     int opt = 0;
  459     int retcode = 0;
  460     int linesize = B64_DEF_LINE_SIZE;
  461     char *infilename = NULL, *outfilename = NULL;
  462 
  463     while( THIS_OPT( argc, argv ) ) {
  464         switch( THIS_OPT(argc, argv) ) {
  465             case 'l':
  466                     linesize = atoi( &(argv[1][2]) );
  467                     if( linesize < B64_MIN_LINE_SIZE ) {
  468                         linesize = B64_MIN_LINE_SIZE;
  469                         printf( "%s\n", b64_message( B64_LINE_SIZE_TO_MIN ) );
  470                     }
  471                     break;
  472             case '?':
  473             case 'h':
  474                     opt = 'h';
  475                     break;
  476             case 'e':
  477             case 'd':
  478                     opt = THIS_OPT(argc, argv);
  479                     break;
  480              default:
  481                     opt = 0;
  482                     break;
  483         }
  484         argv++;
  485         argc--;
  486     }
  487     switch( opt ) {
  488         case 'e':
  489         case 'd':
  490             infilename = argc > 1 ? argv[1] : NULL;
  491             outfilename = argc > 2 ? argv[2] : NULL;
  492             retcode = b64( opt, infilename, outfilename, linesize );
  493             break;
  494         case 0:
  495             retcode = B64_SYNTAX_ERROR;
  496         case 'h':
  497             showuse( opt );
  498             break;
  499 
  500     }
  501     if( retcode ) {
  502         printf( "%s\n", b64_message( retcode ) );
  503     }
  504 
  505     return( retcode );
  506 }