Eu escrevi um script de codificação de base64 para o meu sistema Busybox.
#!/bin/sh
base64encode()
{
/usr/bin/awk -- '
function asc(char,l_found)
{
l_found=0;
for (i=0;i<=255;i++){
if (sprintf("%c",i)==char) l_found=i;
}
return l_found;
}
function base64_and(var,x,l_res,l_i)
{
l_res=0;
for (l_i=0;l_i<8;l_i++){
if (var%2==1 && x%2==1) l_res=l_res/2+128;
else l_res/=2;
var=int(var/2);
x=int(x/2);
}
return l_res;
}
function base64_lshift(var,x)
{
while(x>0){
var*=2;
x--;
}
return var;
}
function base64_rshift(var,x)
{
while(x>0){
var=int(var/2);
x--;
}
return var;
}
BEGIN{
BASE64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
result="";
}
{
while (length($0)>0){
printf "Source: %s Length: %i\n",$0,length($0);
if (length($0)==1){
byte1=asc(substr($0,1,1));
byte2=0;
byte3=0;
}
if (length($0)==2){
byte1=asc(substr($0,1,1));
byte2=asc(substr($0,2,1));
byte3=0;
}
if (length($0)>=3){
byte1=asc(substr($0,1,1));
byte2=asc(substr($0,2,1));
byte3=asc(substr($0,3,1));
}
base1=base64_rshift(byte1,2);
base2=base64_lshift(base64_and(byte1,3),4)+base64_rshift(base64_and(byte2,240),4);
base3=base64_lshift(base64_and(byte2,15),2)+base64_rshift(base64_and(byte3,192),6);
base4=base64_and(byte3,63);
printf "byte1=%i byte2=%i byte3=%i\n", byte1, byte2, byte3;
printf "base1=%i base2=%i base3=%i base4=%i\n", base1, base2, base3, base4;
if (length($0)==1){
result=result substr(BASE64,base1+1,1);
result=result substr(BASE64,base2+1,1);
result=result "==";
$0="";
}
if (length($0)==2){
result=result substr(BASE64,base1+1,1);
result=result substr(BASE64,base2+1,1);
result=result substr(BASE64,base3+1,1);
result=result "=";
$0="";
}
if (length($0)>=3){
result=result substr(BASE64,base1+1,1);
result=result substr(BASE64,base2+1,1);
result=result substr(BASE64,base3+1,1);
result=result substr(BASE64,base4+1,1);
$0=substr($0,4);
}
printf "Result=%s\n", result;
}
printf "%s",result;
}
'
}
base64encode
Mas quando há caracteres NULL na entrada, o awk irá separar a entrada em diferentes registros e fazer a saída do script incorretamente.
Por exemplo:
root@unknown:/tmp/test# echo -e "Hello [root@hp8 ~]# echo -e "Hello #!/bin/sh
base64encode()
{
/usr/bin/awk -- '
function asc(char,l_found)
{
l_found=0;
for (i=0;i<=255;i++){
if (sprintf("%c",i)==char) l_found=i;
}
return l_found;
}
function base64_and(var,x,l_res,l_i)
{
l_res=0;
for (l_i=0;l_i<8;l_i++){
if (var%2==1 && x%2==1) l_res=l_res/2+128;
else l_res/=2;
var=int(var/2);
x=int(x/2);
}
return l_res;
}
function base64_lshift(var,x)
{
while(x>0){
var*=2;
x--;
}
return var;
}
function base64_rshift(var,x)
{
while(x>0){
var=int(var/2);
x--;
}
return var;
}
BEGIN{
BASE64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
result="";
}
{
while (length($0)>0){
printf "Source: %s Length: %i\n",$0,length($0);
if (length($0)==1){
byte1=asc(substr($0,1,1));
byte2=0;
byte3=0;
}
if (length($0)==2){
byte1=asc(substr($0,1,1));
byte2=asc(substr($0,2,1));
byte3=0;
}
if (length($0)>=3){
byte1=asc(substr($0,1,1));
byte2=asc(substr($0,2,1));
byte3=asc(substr($0,3,1));
}
base1=base64_rshift(byte1,2);
base2=base64_lshift(base64_and(byte1,3),4)+base64_rshift(base64_and(byte2,240),4);
base3=base64_lshift(base64_and(byte2,15),2)+base64_rshift(base64_and(byte3,192),6);
base4=base64_and(byte3,63);
printf "byte1=%i byte2=%i byte3=%i\n", byte1, byte2, byte3;
printf "base1=%i base2=%i base3=%i base4=%i\n", base1, base2, base3, base4;
if (length($0)==1){
result=result substr(BASE64,base1+1,1);
result=result substr(BASE64,base2+1,1);
result=result "==";
$0="";
}
if (length($0)==2){
result=result substr(BASE64,base1+1,1);
result=result substr(BASE64,base2+1,1);
result=result substr(BASE64,base3+1,1);
result=result "=";
$0="";
}
if (length($0)>=3){
result=result substr(BASE64,base1+1,1);
result=result substr(BASE64,base2+1,1);
result=result substr(BASE64,base3+1,1);
result=result substr(BASE64,base4+1,1);
$0=substr($0,4);
}
printf "Result=%s\n", result;
}
printf "%s",result;
}
'
}
base64encode
World\!"|base64
SGVsbG8gACBXb3JsZFwhCg==
[root@hp8 ~]#
World!"|./base64encode.sh
Source: Hello Length: 6
byte1=72 byte2=101 byte3=108
base1=18 base2=6 base3=21 base4=44
Result=SGVs
Source: lo Length: 3
byte1=108 byte2=111 byte3=32
base1=27 base2=6 base3=60 base4=32
Result=SGVsbG8g
SGVsbG8gSource: World! Length: 7
byte1=32 byte2=87 byte3=111
base1=8 base2=5 base3=29 base4=47
Result=SGVsbG8gIFdv
Source: rld! Length: 4
byte1=114 byte2=108 byte3=100
base1=28 base2=38 base3=49 base4=36
Result=SGVsbG8gIFdvcmxk
Source: ! Length: 1
byte1=33 byte2=0 byte3=0
base1=8 base2=16 base3=0 base4=0
Result=SGVsbG8gIFdvcmxkIQ==
SGVsbG8gIFdvcmxkIQ==root@unknown:/tmp/test#
Enquanto no Linux, podemos dizer que a saída não estava correta porque a entrada acima foi dividida em dois registros e o caractere NULL entre eles não é processado.
root@unknown:/tmp/test# echo -e "Hello [root@hp8 ~]# echo -e "Hello %pre% World\!"|base64
SGVsbG8gACBXb3JsZFwhCg==
[root@hp8 ~]#
World!"|./base64encode.sh
Source: Hello Length: 6
byte1=72 byte2=101 byte3=108
base1=18 base2=6 base3=21 base4=44
Result=SGVs
Source: lo Length: 3
byte1=108 byte2=111 byte3=32
base1=27 base2=6 base3=60 base4=32
Result=SGVsbG8g
SGVsbG8gSource: World! Length: 7
byte1=32 byte2=87 byte3=111
base1=8 base2=5 base3=29 base4=47
Result=SGVsbG8gIFdv
Source: rld! Length: 4
byte1=114 byte2=108 byte3=100
base1=28 base2=38 base3=49 base4=36
Result=SGVsbG8gIFdvcmxk
Source: ! Length: 1
byte1=33 byte2=0 byte3=0
base1=8 base2=16 base3=0 base4=0
Result=SGVsbG8gIFdvcmxkIQ==
SGVsbG8gIFdvcmxkIQ==root@unknown:/tmp/test#
Alguém pode me dizer como eu posso fazer o awk no meu Busybox tratar toda a entrada com caractere NULL entre um único registro?