You could also solve this problem in a very different way using my printf.exe version 2.11 program.
My printf.exe application is a Windows console program that is a wrapper for the well-known printf CRT function, thus allowing text and formatted numeric values ββto be displayed in the cmd.exe window. In addition, my program printf.exe also allows to perform Reverse Polish Notation arithmetic operations on 32-bit integers and 64-bit double floating-point numbers using the same method and functions of the stack-based Hewlett-Packard calculators.
The new printf.exe version 2.11 also manages character string operations and allows to write scripts (programs) using the simplest programming scheme. The Batch file below contains a printf.exe program that perform a decode of a Base64-encoded string:
@echo off
setlocal
rem Basic Base64 decoding in Aacini's printf.exe
rem Antonio Perez Ayala
rem Download printf.exe package from:
rem https://www.dostips.com/forum/viewtopic.php?f=3&t=7312&p=68956#p68956
goto begin
https://datatracker.ietf.org/doc/html/rfc4648#section-4
+--first octet--+-second octet--+--third octet--+
+-> |7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0| >-+
Decode | +-----------+---+-------+-------+---+-----------+ | Encode
+-< |5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0| <-+
+--1.index--+--2.index--+--3.index--+--4.index--+
The Encoding process converts 3 bytes into 4 characters of the Base64 alphabet.
The Decoding process converts 4 characters from the Base64 alphabet into 3 bytes.
The Base64 alphabet consists of digits, upcase- and lowcase-letters, plus two additional characters:
"+" and "/" for standard conversion, or "-" and "_" for "URL and filename safe" conversion.
:begin
set "Base64Alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
set "Encoded=ZGG01YZq3ZJLbK3Cz1nOhA"
printf "\n" /* Final format */ ^
Base64Alpha /* "ABC..789+/" Enter Base64 alphabet */ ^
]0 /* Store its address in R0 */ ^
Encoded /* "Base64" Enter encoded indices */ ^
getc1 /* 'B' 'a' 's' 'e' '6' '4' 6 Separate individual indices */ ^
( /* WHILE another (group of 4) index? */ ^
==0? ; /* index count == 0 ? QUIT */ ^
/* ===== First index ===== */ ^
shift /* 'a' 's' 'e' '6' '4' 5 'B' Get first index */ ^
[0 /* 'a' 's' 'e' '6' '4' 5 'B' "ABC..789+/" Enter Base64 */ ^
/" <> /" /* 'a' 's' 'e' '6' '4' 5 "ABC..789+/" 'B' Exchange they */ ^
1 dupc /* 'a' 's' 'e' '6' '4' 5 "ABC..789+/" "B" Convert char to string */ ^
index /* 'a' 's' 'e' '6' '4' 5 "ABC..789+/" 1 1 Index position 0-63 and count */ ^
==0? /" < < /" : /* Is not valid index? : Drop count=0 and Base64, and REPEAT */ ^
/" < /" /* 'a' 's' 'e' '6' '4' 5 "ABC..789+/" 1 Drop count */ ^
2 /" << /" /* 'a' 's' 'e' '6' '4' 5 "ABC..789+/" 4 Shift index left 2 bits and get */ ^
/* - first 6 bits of first octet */ ^
]1 /* 'a' 's' 'e' '6' '4' 5 "ABC..789+/" 4 Store they in R1 */ ^
/" < < /" /* 'a' 's' 'e' '6' '4' 5 Drop they and Base64 */ ^
==0? /* IF no more indices? : */ ^
FMT{ "%%c" [1 OUT FMT} ; /* Show previous 6-bits octet and QUIT */ ^
/* ===== Second index ===== */ ^
shift /* 's' 'e' '6' '4' 4 'a' Get second index */ ^
[0 /* 's' 'e' '6' '4' 4 'a' "ABC..789+/" Enter Base64 */ ^
/" <> /" /* 's' 'e' '6' '4' 4 "ABC..789+/" 'a' Exchange they */ ^
1 dupc /* 's' 'e' '6' '4' 4 "ABC..789+/" "a" Convert char to string */ ^
index /* 's' 'e' '6' '4' 4 "ABC..789+/" 26 1 Index position 0-63 and count */ ^
==0? /" < < /" : /* Is not valid index? : Drop count=0 and Base64, and REPEAT */ ^
/" < /" /* 's' 'e' '6' '4' 4 "ABC..789+/" 26 Drop count */ ^
]2 /* 's' 'e' '6' '4' 4 "ABC..789+/" 26 Store 2.index in R2 */ ^
4 /" >> /" /* 's' 'e' '6' '4' 4 "ABC..789+/" 6 Shift 2.index right 4 bits and get */ ^
/* - last 2 bits of first octet */ ^
]+1 /* Complete first octet in R1 */ ^
FMT{ "%%c" [1 OUT FMT} /* Show it */ ^
/" < < /" /* 's' 'e' '6' '4' 4 Drop 2 bits and Base64 */ ^
[2 /* 's' 'e' '6' '4' 4 26 Recover 2.index */ ^
0x0F /" & /" /* 's' 'e' '6' '4' 4 10 Get last 4 bits of 2.index */ ^
4 /" << /" /* 's' 'e' '6' '4' 4 160 Shift they left 4 bits and get */ ^
/* - first 4 bits of second octet */ ^
]2 /* 's' 'e' '6' '4' 4 160 Store they in R2 */ ^
/" < /" /* 's' 'e' '6' '4' 4 Drop they */ ^
==0? /* IF no more indices? : */ ^
FMT{ "%%c" [2 OUT FMT} ; /* Show previous 4-bits octet and QUIT */ ^
/* ===== Third index ===== */ ^
shift /* 'e' '6' '4' 3 's' Get third index */ ^
[0 /* 'e' '6' '4' 3 's' "ABC..789+/" Enter Base64 */ ^
/" <> /" /* 'e' '6' '4' 3 "ABC..789+/" 's' Exchange they */ ^
1 dupc /* 'e' '6' '4' 3 "ABC..789+/" "s" Convert char to string */ ^
index /* 'e' '6' '4' 3 "ABC..789+/" 44 1 Index position 0-63 and count */ ^
==0? /" < < /" : /* Is not valid index? : Drop count=0 and Base64, and REPEAT */ ^
/" < /" /* 'e' '6' '4' 3 "ABC..789+/" 44 Drop count */ ^
]3 /* 'e' '6' '4' 3 "ABC..789+/" 44 Store 3.index in R3 */ ^
2 /" >> /" /* 'e' '6' '4' 3 "ABC..789+/" 11 Shift 3.index right 2 bits and get */ ^
/* - last 4 bits of second octet */ ^
]+2 /* Complete second octet in R2 */ ^
FMT{ "%%c" [2 OUT FMT} /* Show it */ ^
/" < < /" /* 'e' '6' '4' 3 Drop 4 bits and Base64 */ ^
[3 /* 'e' '6' '4' 3 44 Recover 3.index */ ^
0x03 /" & /" /* 'e' '6' '4' 3 0 Get last 2 bits of 3.index */ ^
6 /" << /" /* 'e' '6' '4' 3 0 Shift they left 6 bits and get */ ^
/* - first 2 bits of third octet */ ^
]3 /* 'e' '6' '4' 3 0 Store they in R3 */ ^
/" < /" /* 'e' '6' '4' 3 Drop they */ ^
==0? /* IF no more indices? : */ ^
FMT{ "%%c" [3 OUT FMT} ; /* Show previous 2-bits octet and QUIT */ ^
/* ===== Fourth index ===== */ ^
shift /* '6' '4' 2 'e' Get fourth index */ ^
[0 /* '6' '4' 2 'e' "ABC..789+/" Enter Base64 */ ^
/" <> /" /* '6' '4' 2 "ABC..789+/" 'e' Exchange they */ ^
1 dupc /* '6' '4' 2 "ABC..789+/" "e" Convert char to string */ ^
index /* '6' '4' 2 "ABC..789+/" 30 1 Index position 0-63 and count */ ^
==0? /" < < /" : /* Is not valid index? : Drop count=0 and Base64, and REPEAT */ ^
/" < /" /* '6' '4' 2 "ABC..789+/" 30 Drop count */ ^
/* 4.index contains the last 6 bits of third octet */ ^
]+3 /* Complete third octet in R3 */ ^
FMT{ "%%c" [3 OUT FMT} /* Show it */ ^
/" < < /" /* '6' '4' 2 Drop 6 bits and Base64 */ ^
: /* REPEAT */ ^
) /* ENDWHILE */ ^
OUT /* End the line */
Although it may seem complicated, the printf.exe instructions are very simple. HP calculator users can start writing printf.exe programs in minutes after understanding the differences and the programming scheme. This program could replace the base64
utility you use to decode your Base64 string ZGG01YZq3ZJLbK3Cz1nOhA
(or any other). Also, the same program could be modified to also perform the task of the hexdump
command, but without the spaces, just the way you like it! In the following program, the verbose comments from the first version have been removed, so you can see that the resulting program is really short:
@echo off
if "%~1" == "" echo Usage: %0 base64string & goto :EOF
printf ^
hexa( /* Subroutine to show a char as two hexadecimal digits */ ^
]9 /* Store char in R9 */ ^
FMT{ "%%0.2x" [9 OUT FMT} /* Show it with the proper format */ ^
^< /* Drop it */ ^
) /* End of hexa subroutine */ ^
"\n" "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ]0 "%~1" getc1 ( ==0? ; ^
/* First index: */ /" shift [0 <> 1 dupc index ==0? < < : < 2 << ]1 < < ==0? [1 hexa ; /" ^
/* Second index: */ /" shift [0 <> 1 dupc index ==0? < < : < ]2 4 >> ]+1 [1 hexa < < [2 0x0F & 4 << ]2 < ==0? [2 hexa ; /" ^
/* Third index: */ /" shift [0 <> 1 dupc index ==0? < < : < ]3 2 >> ]+2 [2 hexa < < [3 0x03 & 6 << ]3 < ==0? [3 hexa ; /" ^
/* Fourth index: */ /" shift [0 <> 1 dupc index ==0? < < : < ]+3 [3 hexa < < : ) OUT /"
If you store this program in Base64Decode.bat file, for example, then you can get your result this way:
for /F %%a in ('Base64Decode.bat ZGG01YZq3ZJLbK3Cz1nOhA') do set "readValue1=%%a"
echo %readValue1%
Output:
6461b4d5866add924b6cadc2cf59ce8400
You can download the printf.exe package from this link