Decodes self from base64

assert "c3RyaW5n".decode_base64.to_s == "string"
 assert "c3Rya\nW5n".decode_base64.to_s == "string"
 assert "c3RyaW5nCg==".decode_base64.to_s == "string\n"
 assert "c3RyaW5nCg".decode_base64.to_s == "string\n"
 assert "c3RyaW5neQo=".decode_base64.to_s == "stringy\n"
 assert "c3RyaW5neQo".decode_base64.to_s == "stringy\n"

Property definitions

base64 :: base64 $ CString :: decode_base64
	# Decodes `self` from base64
	#
	#      assert "c3RyaW5n".decode_base64.to_s == "string"
	#      assert "c3Rya\nW5n".decode_base64.to_s == "string"
	#      assert "c3RyaW5nCg==".decode_base64.to_s == "string\n"
	#      assert "c3RyaW5nCg".decode_base64.to_s == "string\n"
	#      assert "c3RyaW5neQo=".decode_base64.to_s == "stringy\n"
	#      assert "c3RyaW5neQo".decode_base64.to_s == "stringy\n"
	#
	private fun decode_base64(length: Int): Bytes do
		if length == 0 then return new Bytes.empty

		# Avoids constant unboxing
		var pad = '='

		var result = new Bytes.with_capacity((length / 4 + 1) * 3)

		var curr = 0
		var cnt = 0
		var endpos = -1
		for i in [0 .. length[ do
			var b = self[i]
			if b == pad then
				endpos = i
				break
			end
			# Ignore whitespaces
			if b <= 0x20 then continue
			if not b.is_base64_char then continue
			curr <<= 6
			curr += b.to_base64_char.to_i
			cnt += 1
			if cnt == 4 then
				result.add ((curr & 0xFF0000) >> 16)
				result.add ((curr & 0xFF00) >> 8)
				result.add (curr & 0xFF)
				curr = 0
				cnt = 0
			end
		end
		if endpos != -1 or cnt != 0 then
			var pads = 0
			for i in [endpos .. length[ do
				var b = self[i]
				if b <= 0x20 then continue
				pads += 1
			end
			if cnt == 2 then
				curr >>= 4
				result.add(curr)
			else if cnt == 3 then
				curr >>= 2
				result.add ((curr & 0xFF00) >> 8)
				result.add (curr & 0xFF)
			end
		end
		return result
	end
lib/base64/base64.nit:106,2--163,4