与字节序无关的 base64_encode/decode 函数
endian-independent base64_encode/decode function
我在谷歌上搜索了我碰巧需要的这两个 C 函数,我遇到的最干净的是 http://fm4dd.com/programming/base64/base64_stringencode_c.htm 但在我看来它就像下面的一小部分......
void decodeblock(unsigned char in[], char *clrstr) {
unsigned char out[4];
out[0] = in[0] << 2 | in[1] >> 4;
out[1] = in[1] << 4 | in[2] >> 2;
out[2] = in[2] << 6 | in[3] >> 0;
out[3] = '[=11=]';
strncat(clrstr, out, sizeof(out));
}
...将依赖于字节序(同上你可以在上面看到的相应的 encodeblack() url)。但它在其他方面很好很干净,不像其他一些:一个有自己的三个头文件,另一个调用它自己的特殊 malloc()-like 函数,等等。任何人都知道一个漂亮、小、干净(没有头文件,没有依赖项等) 版本,像这个,更独立于体系结构?
Edit 我正在寻找这个的原因是 base64_encode() 将在 php 脚本中完成,该脚本是 html 页面,将该编码字符串传递给远处盒子上执行的 cgi 程序。然后那个 cgi 必须 base64_decode() 它。因此,体系结构独立性只是增加了安全性,以防万一 cgi 运行 在非英特尔大端盒(英特尔的小盒)上。
根据下面的评论编辑,这是完整的代码以及我所做的一些更改...
/* downloaded from...
http://fm4dd.com/programming/base64/base64_stringencode_c.htm */
/* ------------------------------------------------------------------------ *
* file: base64_stringencode.c v1.0 *
* purpose: tests encoding/decoding strings with base64 *
* author: 02/23/2009 Frank4DD *
* *
* source: http://base64.sourceforge.net/b64.c for encoding *
* http://en.literateprograms.org/Base64_(C) for decoding *
* ------------------------------------------------------------------------ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* ---- Base64 Encoding/Decoding Table --- */
char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/* decodeblock - decode 4 '6-bit' characters into 3 8-bit binary bytes */
void decodeblock(unsigned char in[], char *clrstr) {
unsigned char out[4];
out[0] = in[0] << 2 | in[1] >> 4;
out[1] = in[1] << 4 | in[2] >> 2;
out[2] = in[2] << 6 | in[3] >> 0;
out[3] = '[=12=]';
strncat(clrstr, out, sizeof(out));
} /* --- end-of-function decodeblock() --- */
char *base64_decode(char *b64src /*, char *clrdst */) {
static char clrdstbuff[8192];
char *clrdst = clrdstbuff;
int c, phase, i;
unsigned char in[4];
char *p;
clrdst[0] = '[=12=]';
phase = 0; i=0;
while(b64src[i]) {
c = (int) b64src[i];
if(c == '=') {
decodeblock(in, clrdst);
break; }
p = strchr(b64, c);
if(p) {
in[phase] = p - b64;
phase = (phase + 1) % 4;
if(phase == 0) {
decodeblock(in, clrdst);
in[0]=in[1]=in[2]=in[3]=0; }
} /* --- end-of-if(p) --- */
i++;
} /* --- end-of-while(b64src[i]) --- */
return ( clrdstbuff );
} /* --- end-of-function base64_decode() --- */
/* encodeblock - encode 3 8-bit binary bytes as 4 '6-bit' characters */
void encodeblock( unsigned char in[], char b64str[], int len ) {
unsigned char out[5];
out[0] = b64[ in[0] >> 2 ];
out[1] = b64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
out[2] = (unsigned char) (len > 1 ? b64[ ((in[1] & 0x0f) << 2) |
((in[2] & 0xc0) >> 6) ] : '=');
out[3] = (unsigned char) (len > 2 ? b64[ in[2] & 0x3f ] : '=');
out[4] = '[=12=]';
strncat(b64str, out, sizeof(out));
} /* --- end-of-function encodeblock() --- */
/* encode - base64 encode a stream, adding padding if needed */
char *base64_encode(char *clrstr /*, char *b64dst */) {
static char b64dstbuff[8192];
char *b64dst = b64dstbuff;
unsigned char in[3];
int i, len = 0;
int j = 0;
b64dst[0] = '[=12=]';
while(clrstr[j]) {
len = 0;
for(i=0; i<3; i++) {
in[i] = (unsigned char) clrstr[j];
if(clrstr[j]) {
len++; j++; }
else in[i] = 0;
} /* --- end-of-for(i) --- */
if( len ) {
encodeblock( in, b64dst, len ); }
} /* --- end-of-while(clrstr[j]) --- */
return ( b64dstbuff );
} /* --- end-of-function base64_encode() --- */
#ifdef TESTBASE64
int main( int argc, char *argv[] ) {
char *mysrc = (argc>1? argv[1] : "My bonnie is over the ocean ");
char *mysrc2 = (argc>2? argv[2] : "My bonnie is over the sea ");
char myb64[2048]="", myb642[2048]="";
char mydst[2048]="", mydst2[2048]="";
char *base64_enclode(), *base64_decode();
int testnum = 1;
if ( strncmp(mysrc,"test",4) == 0 )
testnum = atoi(mysrc+4);
if ( testnum == 1 ) {
strcpy(myb64,base64_encode(mysrc));
printf("The string [%s]\n\tencodes into base64 as: [%s]\n",mysrc,myb64);
strcpy(myb642,base64_encode(mysrc2));
printf("The string [%s]\n\tencodes into base64 as: [%s]\n",mysrc2,myb642);
printf("...\n");
strcpy(mydst,base64_decode(myb64));
printf("The string [%s]\n\tdecodes from base64 as: [%s]\n",myb64,mydst);
strcpy(mydst2,base64_decode(myb642));
printf("The string [%s]\n\tdecodes from base64 as: [%s]\n",myb642,mydst2);
} /* --- end-of-if(testnum==1) --- */
if ( testnum == 2 ) {
strcpy(mydst,base64_decode(mysrc2)); /* input is b64 */
printf("The string [%s]\n\tdecodes from base64 as: [%s]\n",mysrc2,mydst);
} /* --- end-of-if(testnum==2) --- */
if ( testnum == 3 ) {
int itest, ntests = (argc>2?atoi(argv[2]):999);
int ichar, nchars = (argc>3?atoi(argv[3]):128);
unsigned int seed = (argc>4?atoi(argv[4]):987654321);
char blanks[999] = " ";
srand(seed);
for ( itest=1; itest<=ntests; itest++ ) {
for ( ichar=0; ichar<nchars; ichar++ ) mydst[ichar] = 1+(rand()%255);
mydst[nchars] = '[=12=]0';
if ( strlen(blanks) > 0 ) strcat(mydst,blanks);
strcpy(myb64,base64_encode(mydst));
strcpy(mydst2,base64_decode(myb64));
if ( strcmp(mydst,mydst2) != 0 )
printf("Test#%d:\n\t in=%s\n\tout=%s\n",itest,mydst,mydst2);
} /* --- end-of-for(itest) --- */
} /* --- end-of-if(testnum==3) --- */
return 0;
} /* --- end-of-function main() --- */
#endif
不,它不依赖字节序。 Base64本身就是4字节到3字节的编码,并不关心内存中的实际表示。但是,如果您希望传输 little/big 字节序数据,则必须在 编码之前和解码之后对字节序 进行归一化处理。
该片段只是独立地寻址所有字节。如果它在 uint32_t
左右加载 4 个字节并且使用一些位旋转产生的输出将按原样复制到结果缓冲区中,那么它将依赖于字节序。
然而,该代码的 strncat
很危险,并且无法处理嵌入的 NUL 字节。相反,你应该使用类似
void decodeblock(unsigned char in[], unsigned char **clrstr) {
*((*clrstr) ++) = in[0] << 2 | in[1] >> 4;
*((*clrstr) ++) = in[1] << 4 | in[2] >> 2;
*((*clrstr) ++) = in[2] << 6 | in[3] >> 0;
}
这将适用于嵌入式 NUL。
我在谷歌上搜索了我碰巧需要的这两个 C 函数,我遇到的最干净的是 http://fm4dd.com/programming/base64/base64_stringencode_c.htm 但在我看来它就像下面的一小部分......
void decodeblock(unsigned char in[], char *clrstr) {
unsigned char out[4];
out[0] = in[0] << 2 | in[1] >> 4;
out[1] = in[1] << 4 | in[2] >> 2;
out[2] = in[2] << 6 | in[3] >> 0;
out[3] = '[=11=]';
strncat(clrstr, out, sizeof(out));
}
...将依赖于字节序(同上你可以在上面看到的相应的 encodeblack() url)。但它在其他方面很好很干净,不像其他一些:一个有自己的三个头文件,另一个调用它自己的特殊 malloc()-like 函数,等等。任何人都知道一个漂亮、小、干净(没有头文件,没有依赖项等) 版本,像这个,更独立于体系结构?
Edit 我正在寻找这个的原因是 base64_encode() 将在 php 脚本中完成,该脚本是 html 页面,将该编码字符串传递给远处盒子上执行的 cgi 程序。然后那个 cgi 必须 base64_decode() 它。因此,体系结构独立性只是增加了安全性,以防万一 cgi 运行 在非英特尔大端盒(英特尔的小盒)上。
根据下面的评论编辑,这是完整的代码以及我所做的一些更改...
/* downloaded from...
http://fm4dd.com/programming/base64/base64_stringencode_c.htm */
/* ------------------------------------------------------------------------ *
* file: base64_stringencode.c v1.0 *
* purpose: tests encoding/decoding strings with base64 *
* author: 02/23/2009 Frank4DD *
* *
* source: http://base64.sourceforge.net/b64.c for encoding *
* http://en.literateprograms.org/Base64_(C) for decoding *
* ------------------------------------------------------------------------ */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* ---- Base64 Encoding/Decoding Table --- */
char b64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/* decodeblock - decode 4 '6-bit' characters into 3 8-bit binary bytes */
void decodeblock(unsigned char in[], char *clrstr) {
unsigned char out[4];
out[0] = in[0] << 2 | in[1] >> 4;
out[1] = in[1] << 4 | in[2] >> 2;
out[2] = in[2] << 6 | in[3] >> 0;
out[3] = '[=12=]';
strncat(clrstr, out, sizeof(out));
} /* --- end-of-function decodeblock() --- */
char *base64_decode(char *b64src /*, char *clrdst */) {
static char clrdstbuff[8192];
char *clrdst = clrdstbuff;
int c, phase, i;
unsigned char in[4];
char *p;
clrdst[0] = '[=12=]';
phase = 0; i=0;
while(b64src[i]) {
c = (int) b64src[i];
if(c == '=') {
decodeblock(in, clrdst);
break; }
p = strchr(b64, c);
if(p) {
in[phase] = p - b64;
phase = (phase + 1) % 4;
if(phase == 0) {
decodeblock(in, clrdst);
in[0]=in[1]=in[2]=in[3]=0; }
} /* --- end-of-if(p) --- */
i++;
} /* --- end-of-while(b64src[i]) --- */
return ( clrdstbuff );
} /* --- end-of-function base64_decode() --- */
/* encodeblock - encode 3 8-bit binary bytes as 4 '6-bit' characters */
void encodeblock( unsigned char in[], char b64str[], int len ) {
unsigned char out[5];
out[0] = b64[ in[0] >> 2 ];
out[1] = b64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
out[2] = (unsigned char) (len > 1 ? b64[ ((in[1] & 0x0f) << 2) |
((in[2] & 0xc0) >> 6) ] : '=');
out[3] = (unsigned char) (len > 2 ? b64[ in[2] & 0x3f ] : '=');
out[4] = '[=12=]';
strncat(b64str, out, sizeof(out));
} /* --- end-of-function encodeblock() --- */
/* encode - base64 encode a stream, adding padding if needed */
char *base64_encode(char *clrstr /*, char *b64dst */) {
static char b64dstbuff[8192];
char *b64dst = b64dstbuff;
unsigned char in[3];
int i, len = 0;
int j = 0;
b64dst[0] = '[=12=]';
while(clrstr[j]) {
len = 0;
for(i=0; i<3; i++) {
in[i] = (unsigned char) clrstr[j];
if(clrstr[j]) {
len++; j++; }
else in[i] = 0;
} /* --- end-of-for(i) --- */
if( len ) {
encodeblock( in, b64dst, len ); }
} /* --- end-of-while(clrstr[j]) --- */
return ( b64dstbuff );
} /* --- end-of-function base64_encode() --- */
#ifdef TESTBASE64
int main( int argc, char *argv[] ) {
char *mysrc = (argc>1? argv[1] : "My bonnie is over the ocean ");
char *mysrc2 = (argc>2? argv[2] : "My bonnie is over the sea ");
char myb64[2048]="", myb642[2048]="";
char mydst[2048]="", mydst2[2048]="";
char *base64_enclode(), *base64_decode();
int testnum = 1;
if ( strncmp(mysrc,"test",4) == 0 )
testnum = atoi(mysrc+4);
if ( testnum == 1 ) {
strcpy(myb64,base64_encode(mysrc));
printf("The string [%s]\n\tencodes into base64 as: [%s]\n",mysrc,myb64);
strcpy(myb642,base64_encode(mysrc2));
printf("The string [%s]\n\tencodes into base64 as: [%s]\n",mysrc2,myb642);
printf("...\n");
strcpy(mydst,base64_decode(myb64));
printf("The string [%s]\n\tdecodes from base64 as: [%s]\n",myb64,mydst);
strcpy(mydst2,base64_decode(myb642));
printf("The string [%s]\n\tdecodes from base64 as: [%s]\n",myb642,mydst2);
} /* --- end-of-if(testnum==1) --- */
if ( testnum == 2 ) {
strcpy(mydst,base64_decode(mysrc2)); /* input is b64 */
printf("The string [%s]\n\tdecodes from base64 as: [%s]\n",mysrc2,mydst);
} /* --- end-of-if(testnum==2) --- */
if ( testnum == 3 ) {
int itest, ntests = (argc>2?atoi(argv[2]):999);
int ichar, nchars = (argc>3?atoi(argv[3]):128);
unsigned int seed = (argc>4?atoi(argv[4]):987654321);
char blanks[999] = " ";
srand(seed);
for ( itest=1; itest<=ntests; itest++ ) {
for ( ichar=0; ichar<nchars; ichar++ ) mydst[ichar] = 1+(rand()%255);
mydst[nchars] = '[=12=]0';
if ( strlen(blanks) > 0 ) strcat(mydst,blanks);
strcpy(myb64,base64_encode(mydst));
strcpy(mydst2,base64_decode(myb64));
if ( strcmp(mydst,mydst2) != 0 )
printf("Test#%d:\n\t in=%s\n\tout=%s\n",itest,mydst,mydst2);
} /* --- end-of-for(itest) --- */
} /* --- end-of-if(testnum==3) --- */
return 0;
} /* --- end-of-function main() --- */
#endif
不,它不依赖字节序。 Base64本身就是4字节到3字节的编码,并不关心内存中的实际表示。但是,如果您希望传输 little/big 字节序数据,则必须在 编码之前和解码之后对字节序 进行归一化处理。
该片段只是独立地寻址所有字节。如果它在 uint32_t
左右加载 4 个字节并且使用一些位旋转产生的输出将按原样复制到结果缓冲区中,那么它将依赖于字节序。
然而,该代码的 strncat
很危险,并且无法处理嵌入的 NUL 字节。相反,你应该使用类似
void decodeblock(unsigned char in[], unsigned char **clrstr) {
*((*clrstr) ++) = in[0] << 2 | in[1] >> 4;
*((*clrstr) ++) = in[1] << 4 | in[2] >> 2;
*((*clrstr) ++) = in[2] << 6 | in[3] >> 0;
}
这将适用于嵌入式 NUL。