/* * Copyleft (c) 1999, 2016 * ----------------------------------------------------------------------- * Author : scz * Compile : For *nix * : gcc -Wall -pipe -O3 -s -o base64 base64.c * : * : strip base64 or gcc -s * : mcs -d base64 (only for Solaris) * : * Compile : For x86/EWindows XP SP1 & VC 7.1 * : cl base64.c /Febase64.exe /nologo /Os /GB /Gz /Gs65536 /W3 /WX /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /link /RELEASE * : * Create : 2005-04-05 19:43 * Modify : 2006-11-30 13:19 * ----------------------------------------------------------------------- * The only thing they can't take from us are our minds. !H */ #if 0 方便测试一些东西,没有更多其它意义。 $ base64 "\x0\x1" [ 4 bytes ] -> 16 bytes per line 00000000 41 41 45 3D AAE= [ 2 bytes ] -> 16 bytes per line 00000000 00 01 .. $ base64 scz [ 4 bytes ] -> 16 bytes per line 00000000 63 32 4E 36 c2N6 [ 3 bytes ] -> 16 bytes per line 00000000 73 63 7A scz $ base64 nsfocus [ 12 bytes ] -> 16 bytes per line 00000000 62 6E 4E 6D 62 32 4E 31-63 77 3D 3D bnNmb2N1cw== [ 7 bytes ] -> 16 bytes per line 00000000 6E 73 66 6F 63 75 73 nsfocus #endif /************************************************************************ * * * Head File * * * ************************************************************************/ #include #include #include /************************************************************************ * * * Macro * * * ************************************************************************/ #if defined(WIN32) #pragma comment( linker, "/INCREMENTAL:NO" ) #pragma comment( linker, "/merge:.rdata=.text" ) #pragma comment( linker, "/subsystem:console" ) #endif /************************************************************************ * * * Function Prototype * * * ************************************************************************/ static unsigned int base64decode ( unsigned char *in, unsigned int len, unsigned char *out ); static unsigned char base64decodetable ( unsigned char in ); static unsigned int base64encode ( unsigned char *in, unsigned int len, unsigned char *out ); static unsigned char base64encodetable ( unsigned char in ); static unsigned int dosomething ( unsigned char *in, unsigned char *out ); static void hexdump ( FILE *out, unsigned char *in, unsigned int insize, unsigned int count ); /************************************************************************ * * * Static Global Var * * * ************************************************************************/ /************************************************************************/ /* * BASE64解码算法的本质是8进制转16进制 */ static unsigned int base64decode ( unsigned char *in, unsigned int len, unsigned char *out ) { unsigned int x, y, z; unsigned int i, j; unsigned char bufa[4]; unsigned char bufb[3]; /* * 由主调函数确保形参有效性 */ x = ( len - 4 ) / 4; i = j = 0; for ( z = 0; z < x; z++ ) { for ( y = 0; y < 4; y++ ) { bufa[y] = base64decodetable( in[j+y] ); } /* end of for */ out[i] = bufa[0] << 2 | ( bufa[1] & 0x30 ) >> 4; out[i+1] = ( bufa[1] & 0x0F ) << 4 | ( bufa[2] & 0x3C ) >> 2; out[i+2] = ( bufa[2] & 0x03 ) << 6 | ( bufa[3] & 0x3F ); i += 3; j += 4; } /* end of for */ for ( z = 0; z < 4; z++ ) { bufa[z] = base64decodetable( in[j+z] ); } /* end of for */ /* * 编码算法确保了结尾最多有两个'=' */ if ( '=' == in[len-2] ) { y = 2; } else if ( '=' == in[len-1] ) { y = 1; } else { y = 0; } /* * BASE64算法所需填充字节个数是自识别的 */ for ( z = 0; z < y; z++ ) { bufa[4-z-1] = 0x00; } /* end of for */ bufb[0] = bufa[0] << 2 | ( bufa[1] & 0x30 ) >> 4; bufb[1] = ( bufa[1] & 0x0F ) << 4 | ( bufa[2] & 0x3C ) >> 2; bufb[2] = ( bufa[2] & 0x03 ) << 6 | ( bufa[3] & 0x3F ); /* * y必然小于3 */ for ( z = 0; z < 3 - y; z++ ) { out[i+z] = bufb[z]; } /* end of for */ /* * 离开for循环的时候已经z++了 */ i += z; return( i ); } /* end of base64decode */ /* * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" * * 返回0xFF表示失败 */ static unsigned char base64decodetable ( unsigned char in ) { unsigned char out = 0xFF; if ( in >= 'A' && in <= 'Z' ) { out = in - 'A'; } else if ( in >= 'a' && in <= 'z' ) { out = in - 'a' + 26; } else if ( in >= '0' && in <= '9' ) { out = in - '0' + 52; } else if ( '+' == in ) { out = 62; } else if ( '/' == in ) { out = 63; } return( out ); } /* end of base64decodetable */ /* * BASE64编码算法的本质是16进制转8进制 */ static unsigned int base64encode ( unsigned char *in, unsigned int len, unsigned char *out ) { unsigned int x, y, z; unsigned int i, j; unsigned char buf[3]; x = len / 3; y = len % 3; i = j = 0; for ( z = 0; z < x; z++ ) { out[i] = base64encodetable( in[j] >> 2 ); out[i+1] = base64encodetable( ( in[j] & 0x03 ) << 4 | in[j+1] >> 4 ); out[i+2] = base64encodetable( ( in[j+1] & 0x0F ) << 2 | in[j+2] >> 6 ); out[i+3] = base64encodetable( in[j+2] & 0x3F ); i += 4; j += 3; } /* end of for */ if ( 0 != y ) { buf[0] = buf[1] = buf[2] = 0x00; for ( z = 0; z < y; z++ ) { buf[z] = in[j+z]; } /* end of for */ out[i] = base64encodetable( buf[0] >> 2 ); out[i+1] = base64encodetable( ( buf[0] & 0x03 ) << 4 | buf[1] >> 4 ); out[i+2] = base64encodetable( ( buf[1] & 0x0F ) << 2 | buf[2] >> 6 ); out[i+3] = base64encodetable( buf[2] & 0x3F ); i += 4; /* * BASE64算法所需填充字节个数是自识别的 */ for ( z = 0; z < 3 - y; z++ ) { out[i-z-1] = '='; } /* end of for */ } return( i ); } /* end of base64encode */ /* * 显然查表更快,但为了满足我病态的追求程序对称美的心理,决定用函数实现。 * * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" * * 返回0xFF表示失败 */ static unsigned char base64encodetable ( unsigned char in ) { unsigned char out = 0xFF; if ( in <= 25 ) { out = in + 'A'; } else if ( in >= 26 && in <= 51 ) { out = in + 'a' - 26; } else if ( in >= 52 && in <= 61 ) { out = in + '0' - 52; } else if ( 62 == in ) { out = '+'; } else if ( 63 == in ) { out = '/'; } return( out ); } /* end of base64encodetable */ /* * 2005-05-11 09:42 * * 处理\\、\xH、\xHH、\r、\n、\t、\0这几种情形 */ static unsigned int dosomething ( unsigned char *in, unsigned char *out ) { unsigned int i, j; unsigned char str[3]; for ( i = 0, j = 0; '\0' != in[i]; i++, j++ ) { if ( '\\' != in[i] ) { out[j] = in[i]; } else { switch ( in[i+1] ) { case '\\': /* * 出现了两个\ */ out[j] = '\\'; i++; break; case 'r': /* * 出现了\r */ out[j] = '\r'; i++; break; case 'n': /* * 出现了\n */ out[j] = '\n'; i++; break; case 't': /* * 出现了\t */ out[j] = '\t'; i++; break; case '0': /* * 出现了\0 */ out[j] = '\0'; i++; break; case 'x': /* * 出现了\x */ str[1] = str[2] = '\0'; if ( ( in[i+2] >= '0' && in[i+2] <= '9' ) || ( in[i+2] >= 'a' && in[i+2] <= 'f' ) || ( in[i+2] >= 'A' && in[i+2] <= 'F' ) ) { i += 2; str[0] = in[i]; if ( ( in[i+1] >= '0' && in[i+1] <= '9' ) || ( in[i+1] >= 'a' && in[i+1] <= 'f' ) || ( in[i+1] >= 'A' && in[i+1] <= 'F' ) ) { i++; str[1] = in[i]; } /* * 按16进制串处理 */ out[j] = ( unsigned char )strtoul( str, NULL, 16 ); } else { out[j] = in[i]; } break; case '\0': /* * 最后一个\ */ default: /* * 无需转义 */ out[j] = in[i]; break; } /* end of switch */ } } /* end of for */ return( j ); } /* end of dosomething */ /* * 2006-06-09 11:09 scz */ static void hexdump ( FILE *out, unsigned char *in, unsigned int insize, unsigned int count ) { unsigned int offset, k, j, i, m; if ( insize <= 0 || count <= 0 || NULL == in || NULL == out ) { return; } fprintf( out, "[ %u bytes ] -> %u bytes per line\n", insize, count ); i = 0; offset = 0; m = ( count + 1 ) / 2; for ( k = insize / count; k > 0; k--, offset += count ) { fprintf( out, "%08X ", offset ); for ( j = 0; j < count; j++, i++ ) { if ( m == j ) { fprintf( out, "-%02X", in[i] ); } else { fprintf( out, " %02X", in[i] ); } } fprintf( out, " " ); i -= count; for ( j = 0; j < count; j++, i++ ) { /* * if ( isprint( ( int )in[i] ) ) */ if ( ( in[i] >= ' ' ) && ( in[i] != 0x7F ) && ( in[i] < 0xFF ) ) #if 0 if ( ( in[i] >= ' ' ) && ( in[i] < 0x7F ) ) #endif { fprintf( out, "%c", in[i] ); } else { fprintf( out, "." ); } } fprintf( out, "\n" ); } /* end of for */ k = insize - i; if ( k <= 0 ) { return; } fprintf( out, "%08X ", offset ); for ( j = 0 ; j < k; j++, i++ ) { if ( m == j ) { fprintf( out, "-%02X", in[i] ); } else { fprintf( out, " %02X", in[i] ); } } i -= k; for ( j = count - k; j > 0; j-- ) { fprintf( out, " " ); } fprintf( out, " " ); for ( j = 0; j < k; j++, i++ ) { if ( ( in[i] >= ' ' ) && ( in[i] != 0x7F ) && ( in[i] < 0xFF ) ) #if 0 if ( ( in[i] >= ' ' ) && ( in[i] < 0x7F ) ) #endif { fprintf( out, "%c", in[i] ); } else { fprintf( out, "." ); } } fprintf( out, "\n" ); return; } /* end of hexdump */ #if !defined(WIN32) int main ( int argc, char * argv[] ) #else int __cdecl main ( int argc, char * argv[] ) #endif { int ret = EXIT_FAILURE; unsigned int i; unsigned char buf[1024]; if ( argc <= 1 ) { fprintf ( stderr, "Usage: %s \n", argv[0] ); goto main_exit; } i = dosomething( argv[1], argv[1] ); if ( i / 3 * 4 + ( i % 3 ? 4 : 0 ) > 1024 ) { fprintf ( stderr, "Checking your \n" ); goto main_exit; } i = base64encode( argv[1], i, buf ); hexdump( stdout, buf, i, 16 ); i = base64decode( buf, i, argv[1] ); hexdump( stdout, argv[1], i, 16 ); ret = EXIT_SUCCESS; main_exit: return( ret ); } /* end of main */ /************************************************************************/