-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}.