-module(base32_rfc4648). -export([encode/1, decode/1]). -import(base32_utils, [rev_bits_list_to_binary/1]). -spec encode(binary()) -> binary(). encode(Data) -> list_to_binary(encode0(Data)). encode0(Data) -> Size = bit_size(Data), RevEncoded = case 40 - (Size rem 40) of 40 -> encode1(Data, []); 32 -> [$=, $=, $=, $=, $=, $= | encode1(Data, [])]; 24 -> [$=, $=, $=, $= | encode1(Data, [])]; 16 -> [$=, $=, $= | encode1(Data, [])]; 8 -> [$= | encode1(Data, [])] end, lists:reverse(RevEncoded). encode1(<<>>, Accu) -> Accu; encode1(<<0:5, Next/bitstring>>, Accu) -> encode1(Next, [$A | Accu]); encode1(<<1:5, Next/bitstring>>, Accu) -> encode1(Next, [$B | Accu]); encode1(<<2:5, Next/bitstring>>, Accu) -> encode1(Next, [$C | Accu]); encode1(<<3:5, Next/bitstring>>, Accu) -> encode1(Next, [$D | Accu]); encode1(<<4:5, Next/bitstring>>, Accu) -> encode1(Next, [$E | Accu]); encode1(<<5:5, Next/bitstring>>, Accu) -> encode1(Next, [$F | Accu]); encode1(<<6:5, Next/bitstring>>, Accu) -> encode1(Next, [$G | Accu]); encode1(<<7:5, Next/bitstring>>, Accu) -> encode1(Next, [$H | Accu]); encode1(<<8:5, Next/bitstring>>, Accu) -> encode1(Next, [$I | Accu]); encode1(<<9:5, Next/bitstring>>, Accu) -> encode1(Next, [$J | Accu]); encode1(<<10:5, Next/bitstring>>, Accu) -> encode1(Next, [$K | Accu]); encode1(<<11:5, Next/bitstring>>, Accu) -> encode1(Next, [$L | Accu]); encode1(<<12:5, Next/bitstring>>, Accu) -> encode1(Next, [$M | Accu]); encode1(<<13:5, Next/bitstring>>, Accu) -> encode1(Next, [$N | Accu]); encode1(<<14:5, Next/bitstring>>, Accu) -> encode1(Next, [$O | Accu]); encode1(<<15:5, Next/bitstring>>, Accu) -> encode1(Next, [$P | Accu]); encode1(<<16:5, Next/bitstring>>, Accu) -> encode1(Next, [$Q | Accu]); encode1(<<17:5, Next/bitstring>>, Accu) -> encode1(Next, [$R | Accu]); encode1(<<18:5, Next/bitstring>>, Accu) -> encode1(Next, [$S | Accu]); encode1(<<19:5, Next/bitstring>>, Accu) -> encode1(Next, [$T | Accu]); encode1(<<20:5, Next/bitstring>>, Accu) -> encode1(Next, [$U | Accu]); encode1(<<21:5, Next/bitstring>>, Accu) -> encode1(Next, [$V | Accu]); encode1(<<22:5, Next/bitstring>>, Accu) -> encode1(Next, [$W | Accu]); encode1(<<23:5, Next/bitstring>>, Accu) -> encode1(Next, [$X | Accu]); encode1(<<24:5, Next/bitstring>>, Accu) -> encode1(Next, [$Y | Accu]); encode1(<<25:5, Next/bitstring>>, Accu) -> encode1(Next, [$Z | Accu]); encode1(<<26:5, Next/bitstring>>, Accu) -> encode1(Next, [$2 | Accu]); encode1(<<27:5, Next/bitstring>>, Accu) -> encode1(Next, [$3 | Accu]); encode1(<<28:5, Next/bitstring>>, Accu) -> encode1(Next, [$4 | Accu]); encode1(<<29:5, Next/bitstring>>, Accu) -> encode1(Next, [$5 | Accu]); encode1(<<30:5, Next/bitstring>>, Accu) -> encode1(Next, [$6 | Accu]); encode1(<<31:5, Next/bitstring>>, Accu) -> encode1(Next, [$7 | Accu]); encode1(<<0:4>>, Accu) -> [$A | Accu]; encode1(<<1:4>>, Accu) -> [$C | Accu]; encode1(<<2:4>>, Accu) -> [$E | Accu]; encode1(<<3:4>>, Accu) -> [$G | Accu]; encode1(<<4:4>>, Accu) -> [$I | Accu]; encode1(<<5:4>>, Accu) -> [$K | Accu]; encode1(<<6:4>>, Accu) -> [$M | Accu]; encode1(<<7:4>>, Accu) -> [$O | Accu]; encode1(<<8:4>>, Accu) -> [$Q | Accu]; encode1(<<9:4>>, Accu) -> [$S | Accu]; encode1(<<10:4>>, Accu) -> [$U | Accu]; encode1(<<11:4>>, Accu) -> [$W | Accu]; encode1(<<12:4>>, Accu) -> [$Y | Accu]; encode1(<<13:4>>, Accu) -> [$2 | Accu]; encode1(<<14:4>>, Accu) -> [$4 | Accu]; encode1(<<15:4>>, Accu) -> [$6 | Accu]; encode1(<<0:3>>, Accu) -> [$A | Accu]; encode1(<<1:3>>, Accu) -> [$E | Accu]; encode1(<<2:3>>, Accu) -> [$I | Accu]; encode1(<<3:3>>, Accu) -> [$M | Accu]; encode1(<<4:3>>, Accu) -> [$Q | Accu]; encode1(<<5:3>>, Accu) -> [$U | Accu]; encode1(<<6:3>>, Accu) -> [$Y | Accu]; encode1(<<7:3>>, Accu) -> [$4 | Accu]; encode1(<<0:2>>, Accu) -> [$A | Accu]; encode1(<<1:2>>, Accu) -> [$I | Accu]; encode1(<<2:2>>, Accu) -> [$Q | Accu]; encode1(<<3:2>>, Accu) -> [$Y | Accu]; encode1(<<0:1>>, Accu) -> [$A | Accu]; encode1(<<1:1>>, Accu) -> [$Q | Accu]. -spec decode(binary()) -> {ok, binary()} | {error, atom()}. decode(Data) -> decode0(Data, []). decode0(<<>>, Accu) -> {ok, rev_bits_list_to_binary(Accu)}; decode0(<<"A", Next/bitstring>>, Accu) -> decode0(Next, [<<0:5>> | Accu]); decode0(<<"B", Next/bitstring>>, Accu) -> decode0(Next, [<<1:5>> | Accu]); decode0(<<"C", Next/bitstring>>, Accu) -> decode0(Next, [<<2:5>> | Accu]); decode0(<<"D", Next/bitstring>>, Accu) -> decode0(Next, [<<3:5>> | Accu]); decode0(<<"E", Next/bitstring>>, Accu) -> decode0(Next, [<<4:5>> | Accu]); decode0(<<"F", Next/bitstring>>, Accu) -> decode0(Next, [<<5:5>> | Accu]); decode0(<<"G", Next/bitstring>>, Accu) -> decode0(Next, [<<6:5>> | Accu]); decode0(<<"H", Next/bitstring>>, Accu) -> decode0(Next, [<<7:5>> | Accu]); decode0(<<"I", Next/bitstring>>, Accu) -> decode0(Next, [<<8:5>> | Accu]); decode0(<<"J", Next/bitstring>>, Accu) -> decode0(Next, [<<9:5>> | Accu]); decode0(<<"K", Next/bitstring>>, Accu) -> decode0(Next, [<<10:5>> | Accu]); decode0(<<"L", Next/bitstring>>, Accu) -> decode0(Next, [<<11:5>> | Accu]); decode0(<<"M", Next/bitstring>>, Accu) -> decode0(Next, [<<12:5>> | Accu]); decode0(<<"N", Next/bitstring>>, Accu) -> decode0(Next, [<<13:5>> | Accu]); decode0(<<"O", Next/bitstring>>, Accu) -> decode0(Next, [<<14:5>> | Accu]); decode0(<<"P", Next/bitstring>>, Accu) -> decode0(Next, [<<15:5>> | Accu]); decode0(<<"Q", Next/bitstring>>, Accu) -> decode0(Next, [<<16:5>> | Accu]); decode0(<<"R", Next/bitstring>>, Accu) -> decode0(Next, [<<17:5>> | Accu]); decode0(<<"S", Next/bitstring>>, Accu) -> decode0(Next, [<<18:5>> | Accu]); decode0(<<"T", Next/bitstring>>, Accu) -> decode0(Next, [<<19:5>> | Accu]); decode0(<<"U", Next/bitstring>>, Accu) -> decode0(Next, [<<20:5>> | Accu]); decode0(<<"V", Next/bitstring>>, Accu) -> decode0(Next, [<<21:5>> | Accu]); decode0(<<"W", Next/bitstring>>, Accu) -> decode0(Next, [<<22:5>> | Accu]); decode0(<<"X", Next/bitstring>>, Accu) -> decode0(Next, [<<23:5>> | Accu]); decode0(<<"Y", Next/bitstring>>, Accu) -> decode0(Next, [<<24:5>> | Accu]); decode0(<<"Z", Next/bitstring>>, Accu) -> decode0(Next, [<<25:5>> | Accu]); decode0(<<"2", Next/bitstring>>, Accu) -> decode0(Next, [<<26:5>> | Accu]); decode0(<<"3", Next/bitstring>>, Accu) -> decode0(Next, [<<27:5>> | Accu]); decode0(<<"4", Next/bitstring>>, Accu) -> decode0(Next, [<<28:5>> | Accu]); decode0(<<"5", Next/bitstring>>, Accu) -> decode0(Next, [<<29:5>> | Accu]); decode0(<<"6", Next/bitstring>>, Accu) -> decode0(Next, [<<30:5>> | Accu]); decode0(<<"7", Next/bitstring>>, Accu) -> decode0(Next, [<<31:5>> | Accu]); decode0(<<"======">>, [<<0:5>> | Accu]) -> decode0(<<>>, [<<0:3>> | Accu]); decode0(<<"======">>, [<<4:5>> | Accu]) -> decode0(<<>>, [<<1:3>> | Accu]); decode0(<<"======">>, [<<8:5>> | Accu]) -> decode0(<<>>, [<<2:3>> | Accu]); decode0(<<"======">>, [<<12:5>> | Accu]) -> decode0(<<>>, [<<3:3>> | Accu]); decode0(<<"======">>, [<<16:5>> | Accu]) -> decode0(<<>>, [<<4:3>> | Accu]); decode0(<<"======">>, [<<20:5>> | Accu]) -> decode0(<<>>, [<<5:3>> | Accu]); decode0(<<"======">>, [<<24:5>> | Accu]) -> decode0(<<>>, [<<6:3>> | Accu]); decode0(<<"======">>, [<<28:5>> | Accu]) -> decode0(<<>>, [<<7:3>> | Accu]); decode0(<<"====">>, [<<0:5>> | Accu]) -> decode0(<<>>, [<<0:1>> | Accu]); decode0(<<"====">>, [<<16:5>> | Accu]) -> decode0(<<>>, [<<1:1>> | Accu]); decode0(<<"===">>, [<<0:5>> | Accu]) -> decode0(<<>>, [<<0:4>> | Accu]); decode0(<<"===">>, [<<2:5>> | Accu]) -> decode0(<<>>, [<<1:4>> | Accu]); decode0(<<"===">>, [<<4:5>> | Accu]) -> decode0(<<>>, [<<2:4>> | Accu]); decode0(<<"===">>, [<<6:5>> | Accu]) -> decode0(<<>>, [<<3:4>> | Accu]); decode0(<<"===">>, [<<8:5>> | Accu]) -> decode0(<<>>, [<<4:4>> | Accu]); decode0(<<"===">>, [<<10:5>> | Accu]) -> decode0(<<>>, [<<5:4>> | Accu]); decode0(<<"===">>, [<<12:5>> | Accu]) -> decode0(<<>>, [<<6:4>> | Accu]); decode0(<<"===">>, [<<14:5>> | Accu]) -> decode0(<<>>, [<<7:4>> | Accu]); decode0(<<"===">>, [<<16:5>> | Accu]) -> decode0(<<>>, [<<8:4>> | Accu]); decode0(<<"===">>, [<<18:5>> | Accu]) -> decode0(<<>>, [<<9:4>> | Accu]); decode0(<<"===">>, [<<20:5>> | Accu]) -> decode0(<<>>, [<<10:4>> | Accu]); decode0(<<"===">>, [<<22:5>> | Accu]) -> decode0(<<>>, [<<11:4>> | Accu]); decode0(<<"===">>, [<<24:5>> | Accu]) -> decode0(<<>>, [<<12:4>> | Accu]); decode0(<<"===">>, [<<26:5>> | Accu]) -> decode0(<<>>, [<<13:4>> | Accu]); decode0(<<"===">>, [<<28:5>> | Accu]) -> decode0(<<>>, [<<14:4>> | Accu]); decode0(<<"===">>, [<<30:5>> | Accu]) -> decode0(<<>>, [<<15:4>> | Accu]); decode0(<<"=">>, [<<0:5>> | Accu]) -> decode0(<<>>, [<<0:2>> | Accu]); decode0(<<"=">>, [<<8:5>> | Accu]) -> decode0(<<>>, [<<1:2>> | Accu]); decode0(<<"=">>, [<<16:5>> | Accu]) -> decode0(<<>>, [<<2:2>> | Accu]); decode0(<<"=">>, [<<24:5>> | Accu]) -> decode0(<<>>, [<<3:2>> | Accu]); decode0(_, _) -> {error, invalid_format}.