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