OpenVMS Source-Code Demos
BASE64_DECODE
1000 %title "base64_decode" !
%ident "version 100.2" ! <---+
declare string constant k_version = "100.2" , ! <---+ &
k_program = "base64_decode" !
!=======================================================================
! title : base64_decode_xxx.bas
! author : Neil Rieck
! created : 2001-02-11
! refereces: http://www.faqs.org/rfcs/rfc3548.html
! http://www.faqs.org/rfcs/rfc4648.html
!
! ver who when what
! --- --- -------- -----------------------------------------------------
! 100 NSR 20010211 1. original work
! NSR 20120927 2. renamed some variables; added some documentation
!=======================================================================
option type = explicit , ! cuz tricks are for kids &
size = integer quad , ! &
size = real xfloat !
!
declare string buf0$ , !&
buf1$ , !&
junk$ , !&
long i% , !&
j% , !&
k% , !&
junk% !
!=======================================================================
! main
!=======================================================================
main:
print "-i- program: "+ k_program +"_"+ k_version !
print string$(len(k_program +"_"+ k_version), asc("=")) ! what will the optimizer do with this?
!
!-----------------------------------------------------------------------
! test cases (single character text)
! includes: 7-bit ascii, 8-bit ascii, iso-8859-1
!-----------------------------------------------------------------------
buf0$ = "QQ=="
gosub base64_decode
print "in : ";buf0$
print "expected: A"
print "out : ";buf1$
print
!
buf0$ = "QUI="
gosub base64_decode
print "in : ";buf0$
print "expected: AB"
print "out : ";buf1$
print
!
buf0$ = "QUJD"
gosub base64_decode
print "in : ";buf0$
print "expected: ABC"
print "out : ";buf1$
print
!
buf0$ = "ABCD"
gosub base64_decode
print "in : ";buf0$
print "expected: ABCD"
print "out : ";buf1$
print
!
buf0$ = "VGhlIFJhbWFucyBkbyBldmVyeXRoaW5nIGluIHRocmVlcw=="
gosub base64_decode
print "in : ";buf0$
print "expected: The Ramans do everything in threes"
print "out : ";buf1$
print
!
buf0$ = "SXQgd2FzIHRoZSBkYXduIG9mIHRoZSB0aGlyZCBhZ2Ugb2YgbWFua2luZCwgdGVuIHllYXJzIGFmdGVyIH" +&
"RoZSBFYXJ0aC1NaW5iYXJpIFdhci4gVGhlIEJhYnlsb24gUHJvamVjdCB3YXMgYSBkcmVhbSBnaXZlbiBm" +&
"b3JtLiBJdHMgZ29hbDogdG8gcHJldmVudCBhbm90aGVyIHdhciBieSBjcmVhdGluZyBhIHBsYWNlIHdoZX" +&
"JlIGh1bWFucyBhbmQgYWxpZW5zIGNvdWxkIHdvcmsgb3V0IHRoZWlyIGRpZmZlcmVuY2VzIHBlYWNlZnVsbHku"
gosub base64_decode
print "in : ";buf0$
print "expected: It was the dawn of the third age of mankind, ten years after the Earth-Minbari War. "+&
"The Babylon Project was a dream given form. Its goal: to prevent another war by creating a "+&
"place where humans and aliens could work out their differences peacefully."
print "out : ";buf1$
print
!
!-----------------------------------------------------------------------
! test cases (multi-byte text)
! includes: utf-8 (http://en.wikipedia.org/wiki/UTF-8)
!-----------------------------------------------------------------------
! comming
!
!-----------------------------------------------------------------------
! test cases (2-character text)
! includes: utf-16 (http://en.wikipedia.org/wiki/UTF-16)
!-----------------------------------------------------------------------
! comming
!
!-----------------------------------------------------------------------
! test cases (3-character text)
! includes: utf-32/ucs-4 (http://en.wikipedia.org/wiki/UTF-32)
!-----------------------------------------------------------------------
! comming
!
goto fini ! adios
!
!====================================================================================================
! <<< base64 support >>>
!
! encoding notes:
! 1. each 24-bit group (3 bytes) is transmitted as 4 characters each representing 6 bits
! 2. characters must be sent in multiples of 4 (padding is appended as required)
! 3. the "=" char means PAD or SPECIAL processing
! 4. A=0, B=1, C=2, etc.
! 5. examples:
! 5.1 A QQ==
! A = ascii:65 = 8-bit:01000001 24-bit:010000 01xxxx xxxxxx xxxxxx
! aaaaaa aa
! 5.2 AB QUI=
! B = ascii:66 = 8-bit:01000010 24-bit:010000 010100 0010xx xxxxxx
! aaaaaa aabbbb bbbb
! 5.3 ABC QUJD
! C = ascii:67 = 8-bit:01000011 24-bit:010000 010100 001001 000011
! aaaaaa aabbbb bbbbcc cccccc
! 5.4 ABCD QUJDRA==
! D = ascii:68 = 8-bit:01000100 24-bit:010000 010100 001001 000011 010001 00xxxx
! aaaaaa aabbbb bbbbcc cccccc dddddd dd
! 5.5 THIS IS A TEST VEhJUyBJUyBBIFRFU1Q=
! 6. bit-mapping schematic:
!
! +--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|
! +-----------+---+-------+-------+---+-----------+
! |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--+
!
! 7. bit-mapping example:
! M| a| n example unencoded data
! 77| 97| 110 ASCII value
! 7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0|7 6 5 4 3 2 1 0 bits (3 sets of 8)
! ---------------+---------------+---------------
! 0 1 0 0 1 1 0 1 0 1 1 0 0 0 0 1 0 1 1 0 1 1 1 0 example bit stream
! -----------+-----------+-----------+-----------
! 5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0|5 4 3 2 1 0 bits (4 sets of 6)
! 19| 22| 5| 46 base64 value
! T| W| F| u example base64 encoded symbols
!====================================================================================================
! entry: buf0$ contains base64 encoded data
! exit: buf1$ contains the decoded data (if no errors)
!====================================================================================================
! position #2 (weight #1) --+ position #65 (weight #64) --+
! position #1 (weight #0) -+| position #64 (weight #63) -+|
declare string constant base64$ = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
!
! note: MAP declarations with identical names are overlaid
!
map(switch) long switch_long ! one 32-bit integer
map(switch) byte switch_byte(3) ! 0->3 eight-bit bytes
!
declare long pad_count% !
!
10000 base64_decode: !
buf1$ = "" ! init
junk% = mod(len(buf0$),4) ! do a sanity test
if junk% <> 0 then !
print cr+lf+bel+"-e-error, BASE-64 line is not a multiple of 4" !
print "-i-debug-len:"+ str$(len(buf0$)) !
print "-i-debug-dat>"+ buf0$ +"<" !
goto base64_decode_exit !
end if !
for i% = 1 to len(buf0$) step 4 ! scan symbols by four
switch_long = 0 ! init this each pass through
pad_count% = 0 ! init this each pass through
for j% = 0 to 3 ! scoop up four symbols each pass thru
junk$ = mid$(buf0$, i%+j%, 1) ! select a base64 symbol from buf0$
if junk$ = "=" then ! if just a padding character
pad_count% = pad_count% + 1 ! then skip it (but count it)
else ! else not a padding character
k% = pos(base64$, junk$, 1) ! find position in string
if k% = 0 then !
print "-e-oops, '"+ junk$ +"' is not a legal base64 symbol"
goto base64_decode_error_exit ! exit on a lookup error
else !
k% = k% - 1 ! convert position to weight
end if !
!~~~ switch_long = switch_long + (k% * (64%^(3%-j%))) x k x 64^2, k x 64^1, k x 64^0
! Here, OR is the same as PLUS
switch_long = switch_long or (k% * (64%^(3%-j%))) ! k x 64^2, k x 64^1, k x 64^0
end if !
next j% !
!
! Caveat: the next stub is ENDIAN dependant (http://en.wikipedia.org/wiki/Endian)
! 1) for little ENDIAN architectures use: 2->0
! architecures: x86, x86-64, DEC-PDP-11, DEC-VAX, DEC-Alpha
! 2) for big ENDIAN architectures use: 1->3
! architecures: 32-bit SPARC V8
! 3) many 64-bit architectures are bi-ENDIAN so desired coding here would depend upon settings by the host OS
! architecures: 64-bit SPARC V9, Itanium (IA-64)
! examples>> OpenVMS on Itanium : little
! All flavors of LINIX on Itanium : little
! Most flavours of UNIX on Itanium: little
! HP-UX on Itanium : big
!
print_base64: !
%let %endian=0 ! 0=little endian
%if %endian=0 %then ! LITTLE ENDIAN - ignore greatest (last) byte
for k% = 2 to pad_count% step -1 ! we want "2-1-0" or "2-1" or "2" (we always skip 3)
%else ! BIG ENDIAN - ignore greatest (first) byte
for k% = (pad_count% + 1) to 3 ! we want "1-2-3" or "2-3" or "3" (we always skip 0)
%end %if !
junk% = switch_byte(k%) ! get 8 bit data
junk% = junk% + 256 if junk% < 0 ! convert unsigned to signed
buf1$ = buf1$ + chr$(junk%) !
next k% !
next i% !
!
base64_decode_exit: !
return !
base64_decode_error_exit: !
buf1$ = "" ! zap
return !
!=======================================================================
! adios
!=======================================================================
fini:
end