core :: union_find
union–find algorithm using an efficient disjoint-set data structureFileServer action, which is a standard and minimal file server
			restful annotation documented at lib/nitcorn/restful.nit
			root to execute
			
# Offers the base 64 encoding and decoding algorithms
module base64
redef class Char
	# Is `self` a valid Base64 character ?
	fun is_base64_char: Bool do
		if code_point >= 127 then return false
		return code_point.is_base64_char
	end
end
redef class Int
	# Is `self` a valid Base64 character ?
	fun is_base64_char: Bool do
		if self == u'+' then return true
		if self == u'/' then return true
		if self > u'Z' then
			if self < u'a' then return false
			if self <= u'z' then return true
			return false
		end
		if self >= u'A' then return true
		if self <= u'9' and self >= u'0' then return true
		return false
	end
	# Returns the `base64` equivalent of `self`
	#
	# REQUIRE `self`.`is_base64_char`
	fun to_base64_char: Int do
		if self == u'+' then return 62
		if self == u'/' then return 63
		if self > u'Z' then
			if self < u'a' then abort
			if self <= u'z' then return self - 71
			abort
		end
		if self >= u'A' then return self - 0x41
		if self <= u'9' and self >= u'0' then return self + 4
		abort
	end
end
redef class CString
	# Alphabet used by the base64 algorithm
	private fun base64_chars : Bytes
	do
		return b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
	end
	# Encodes `self` to base64.
	#
	# By default, uses "=" for padding.
	#
	#     assert "string".encode_base64 == "c3RyaW5n"
	private fun encode_base64(length: Int): Bytes do
		var base64_bytes = once base64_chars
		var steps = length / 3
		var bytes_in_last_step = length % 3
		var result_length = steps * 4
		if bytes_in_last_step > 0 then result_length += 4
		var result = new Bytes.with_capacity(result_length)
		var in_off = 0
		for s in [0 .. steps[ do
			var ind = (self[in_off] & 0b1111_1100) >> 2
			result.add base64_bytes[ind]
			ind = ((self[in_off] & 0b0000_0011) << 4) | ((self[in_off + 1] & 0b1111_0000) >> 4)
			result.add base64_bytes[ind]
			ind = ((self[in_off + 1] & 0b0000_1111) << 2) | ((self[in_off + 2] & 0b1100_0000) >> 6)
			result.add base64_bytes[ind]
			ind = (self[in_off + 2] & 0b0011_1111)
			result.add base64_bytes[ind]
			in_off += 3
		end
		if bytes_in_last_step == 1 then
			result.add base64_bytes[(self[in_off] & 0b1111_1100) >> 2]
			result.add base64_bytes[(self[in_off] & 0b0000_0011) << 4]
		else if bytes_in_last_step == 2 then
			result.add base64_bytes[(self[in_off] & 0b1111_1100) >> 2]
			result.add base64_bytes[((self[in_off] & 0b0000_0011) << 4) | ((self[in_off + 1] & 0b1111_0000) >> 4)]
			result.add base64_bytes[(self[in_off + 1] & 0b0000_1111) << 2]
		end
		var rempad = if bytes_in_last_step > 0 then 3 - bytes_in_last_step else 0
		for i in [0 .. rempad[ do result.add u'='
		return result
	end
	# 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
	# Is `self` a well-formed Base64 entity ?
	#
	# ~~~nit
	#	assert "Qn03".is_base64
	#	assert not "#sd=".is_base64
	# ~~~
	fun is_base64(length: Int): Bool do return check_base64(length) == null
	# Is `self` a well-formed Base64 entity ?
	#
	# Will return an Error otherwise with info on which part is erroneous.
	fun check_base64(length: Int): nullable Error do
		var rlen = 0
		var opos = length
		for i in [0 .. length[ do
			if self[i] == u'=' then
				opos = i
				break
			end
			if self[i].is_whitespace then continue
			if not self[i].is_base64_char then return new Error("Invalid Base64 character at position {i}: {self[i].code_point}")
			rlen += 1
			if rlen > 4 then rlen -= 4
		end
		var pad = 0
		for i in [opos .. length[ do
			if self[i].is_whitespace then continue
			if self[i] != u'=' then return new Error("Invalid padding character {self[i].code_point} at position {i}")
			pad += 1
		end
		if rlen + pad != 4 then return new Error("Invalid padding length")
		return null
	end
end
redef class Bytes
	# Encodes the receiver string to base64 using a custom padding character.
	#
	# If using the default padding character `=`, see `encode_base64`.
	fun encode_base64: Bytes do return items.encode_base64(length)
	# Decodes the receiver string to base64 using a custom padding character.
	#
	# Default padding character `=`
	fun decode_base64: Bytes do return items.decode_base64(length)
	# Is `self` a well-formed Base64 entity ?
	fun is_base64: Bool do return items.is_base64(length)
	# Is `self` a well-formed Base64 entity ?
	#
	# Will return an Error otherwise with info on which part is erroneous.
	fun check_base64: nullable Error do return items.check_base64(length)
end
redef class Text
	# Encodes the receiver string to base64 using a custom padding character.
	#
	# If using the default padding character `=`, see `encode_base64`.
	fun encode_base64: String do return to_cstring.encode_base64(byte_length).to_s
	# Decodes the receiver string to base64 using a custom padding character.
	#
	# Default padding character `=`
	fun decode_base64: Bytes do return to_cstring.decode_base64(byte_length)
	# Is `self` a well-formed Base64 entity ?
	fun is_base64: Bool do return to_cstring.is_base64(byte_length)
	# Is `self` a well-formed Base64 entity ?
	#
	# Will return an Error otherwise with info on which part is erroneous.
	fun check_base64: nullable Error do return to_cstring.check_base64(byte_length)
end
redef class FlatText
	redef fun encode_base64 do return fast_cstring.encode_base64(byte_length).to_s
	redef fun decode_base64 do return fast_cstring.decode_base64(byte_length)
	redef fun is_base64 do return fast_cstring.is_base64(byte_length)
	redef fun check_base64 do return fast_cstring.check_base64(byte_length)
end
lib/base64/base64.nit:17,1--250,3